From 4a5bcbb4e4fb402719d0d6c4da17a3ca43be66c2 Mon Sep 17 00:00:00 2001 From: chloekek Date: Mon, 15 Apr 2024 00:23:05 +0200 Subject: Add vec_deque::Iter::as_slices and friends Add the following methods, that work similarly to VecDeque::as_slices: - alloc::collections::vec_deque::Iter::as_slices - alloc::collections::vec_deque::IterMut::into_slices - alloc::collections::vec_deque::IterMut::as_slices - alloc::collections::vec_deque::IterMut::as_mut_slices Obtaining slices from a VecDeque iterator was not previously possible. --- library/alloc/src/collections/vec_deque/iter.rs | 34 +++++++ .../alloc/src/collections/vec_deque/iter_mut.rs | 107 +++++++++++++++++++++ library/alloc/src/lib.rs | 1 + 3 files changed, 142 insertions(+) diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index 5a5e7f70854..74eeed3f9e1 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -19,6 +19,40 @@ impl<'a, T> Iter<'a, T> { pub(super) fn new(i1: slice::Iter<'a, T>, i2: slice::Iter<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// This has the same lifetime as the original `VecDeque`, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&'a [T], &'a [T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 5061931afb7..db81f0d1e1d 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -19,6 +19,113 @@ impl<'a, T> IterMut<'a, T> { pub(super) fn new(i1: slice::IterMut<'a, T>, i2: slice::IterMut<'a, T>) -> Self { Self { i1, i2 } } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut` references that alias, this is forced to + /// consume the iterator. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// let slices = iter.into_slices(); + /// slices.0[0] = 42; + /// slices.1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn into_slices(self) -> (&'a mut [T], &'a mut [T]) { + (self.i1.into_slice(), self.i2.into_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// assert_eq!(iter.as_slices(), (&[9, 10][..], &[0, 1][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_slices(&self) -> (&[T], &[T]) { + (self.i1.as_slice(), self.i2.as_slice()) + } + + /// Views the underlying data as a pair of subslices of the original data. + /// + /// The slices contain, in order, the contents of the deque not yet yielded + /// by the iterator. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slices + /// borrow their lifetimes from the iterator the method is applied on. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_iter_as_slices)] + /// + /// use std::collections::VecDeque; + /// + /// let mut deque = VecDeque::new(); + /// deque.push_back(0); + /// deque.push_back(1); + /// deque.push_back(2); + /// deque.push_front(10); + /// deque.push_front(9); + /// deque.push_front(8); + /// + /// let mut iter = deque.iter_mut(); + /// iter.next(); + /// iter.next_back(); + /// + /// iter.as_mut_slices().0[0] = 42; + /// iter.as_mut_slices().1[0] = 24; + /// assert_eq!(deque.as_slices(), (&[8, 42, 10][..], &[24, 1, 2][..])); + /// ``` + #[unstable(feature = "vec_deque_iter_as_slices", issue = "123947")] + pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { + (self.i1.as_mut_slice(), self.i2.as_mut_slice()) + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index dec04d7e421..9862af7f1e7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -150,6 +150,7 @@ #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] #![feature(slice_index_methods)] +#![feature(slice_iter_mut_as_mut_slice)] #![feature(slice_ptr_get)] #![feature(slice_range)] #![feature(std_internals)] -- cgit 1.4.1-3-g733a5 From 26c4893ae6a6bd5d611fd6c7b3c803a720138d40 Mon Sep 17 00:00:00 2001 From: Gabriel Bjørnager Jensen Date: Tue, 24 Sep 2024 22:40:29 +0200 Subject: Mark 'get_mut' and 'set_position' in 'std::io::Cursor' as const; --- library/std/src/io/cursor.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 9f913eae095..fbfdb4fa023 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -153,7 +153,8 @@ impl Cursor { /// let reference = buff.get_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn get_mut(&mut self) -> &mut T { &mut self.inner } @@ -200,7 +201,8 @@ impl Cursor { /// assert_eq!(buff.position(), 4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_position(&mut self, pos: u64) { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn set_position(&mut self, pos: u64) { self.pos = pos; } } -- cgit 1.4.1-3-g733a5 From 3727a8c4d8169043a40f327dbd39db0c4448aef6 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 1 Sep 2024 04:20:20 +0530 Subject: uefi: process: Add args support - Wrap all args with quotes. - Escape ^ and " inside quotes using ^. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 68 +++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index fdc5f5d7e4f..4494b3df57b 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -18,6 +18,7 @@ use crate::{fmt, io}; #[derive(Debug)] pub struct Command { prog: OsString, + args: Vec, stdout: Option, stderr: Option, } @@ -39,12 +40,11 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), stdout: None, stderr: None } + Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } } - // FIXME: Implement arguments as reverse of parsing algorithm - pub fn arg(&mut self, _arg: &OsStr) { - panic!("unsupported") + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_os_string()); } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -72,7 +72,7 @@ impl Command { } pub fn get_args(&self) -> CommandArgs<'_> { - panic!("unsupported") + CommandArgs { iter: self.args.iter() } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -116,6 +116,12 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; + // UEFI adds the bin name by default + if !self.args.is_empty() { + let args = uefi_command_internal::create_args(&self.prog, &self.args); + cmd.set_args(args); + } + // Setup Stdout let stdout = self.stdout.unwrap_or(Stdio::MakePipe); let stdout = Self::create_pipe(stdout)?; @@ -315,7 +321,7 @@ mod uefi_command_internal { stdout: Option>, stderr: Option>, st: OwnedTable, - args: Option>, + args: Option<(*mut u16, usize)>, } impl Image { @@ -449,20 +455,20 @@ mod uefi_command_internal { } } - pub fn set_args(&mut self, args: &OsStr) { + pub fn set_args(&mut self, args: Box<[u16]>) { let loaded_image: NonNull = helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); - let mut args = args.encode_wide().collect::>(); - let args_size = (crate::mem::size_of::() * args.len()) as u32; + let len = args.len(); + let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap(); + let ptr = Box::into_raw(args).as_mut_ptr(); unsafe { - (*loaded_image.as_ptr()).load_options = - args.as_mut_ptr() as *mut crate::ffi::c_void; + (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void; (*loaded_image.as_ptr()).load_options_size = args_size; } - self.args = Some(args); + self.args = Some((ptr, len)); } fn update_st_crc32(&mut self) -> io::Result<()> { @@ -502,6 +508,10 @@ mod uefi_command_internal { ((*bt.as_ptr()).unload_image)(self.handle.as_ptr()); } } + + if let Some((ptr, len)) = self.args { + let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) }; + } } } @@ -681,4 +691,38 @@ mod uefi_command_internal { } } } + + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { + const QUOTE: u16 = 0x0022; + const SPACE: u16 = 0x0020; + const CARET: u16 = 0x005e; + const NULL: u16 = 0; + + // This is the lower bound on the final length under the assumption that + // the arguments only contain ASCII characters. + let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum()); + + // Wrap program name in quotes to avoid any problems + res.push(QUOTE); + res.extend(prog.encode_wide()); + res.push(QUOTE); + res.push(SPACE); + + for arg in args { + // Wrap the argument in quotes to be treat as single arg + res.push(QUOTE); + for c in arg.encode_wide() { + // CARET in quotes is used to escape CARET or QUOTE + if c == QUOTE || c == CARET { + res.push(CARET); + } + res.push(c); + } + res.push(QUOTE); + + res.push(SPACE); + } + + res.into_boxed_slice() + } } -- cgit 1.4.1-3-g733a5 From 5f443df4044532d95c23aa8d97f2748ca287378f Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Sat, 2 Nov 2024 11:39:29 -0600 Subject: Add #[rustc_as_ptr] attribute --- compiler/rustc_feature/src/builtin_attrs.rs | 5 +++++ compiler/rustc_passes/src/check_attr.rs | 3 +++ compiler/rustc_span/src/symbol.rs | 1 + 3 files changed, 9 insertions(+) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0069b07ad62..95cb7f4fff5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -875,6 +875,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items, "lang items are subject to change", ), + rustc_attr!( + rustc_as_ptr, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, + "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations." + ), rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0a2926c0404..8d70c9db12c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -162,6 +162,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_std_internal_symbol(attr, span, target) } [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), + [sym::rustc_as_ptr, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } [sym::rustc_never_returns_null_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 890c4fdafef..dde6b83c151 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1652,6 +1652,7 @@ symbols! { rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, rustc_allowed_through_unstable_modules, + rustc_as_ptr, rustc_attrs, rustc_autodiff, rustc_box, -- cgit 1.4.1-3-g733a5 From 37c30aeb45d33b14dadb6c06c3f71b8e047bd2fe Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:27:09 -0700 Subject: Check for #[rustc_as_ptr] attribute instead of searching for function names Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- compiler/rustc_lint/src/dangling.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index a34c3e26778..09fe709e845 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -133,10 +133,11 @@ impl DanglingPointerSearcher<'_, '_> { fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind - && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr) + && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.has_attr(fn_id, sym::rustc_as_ptr) && is_temporary_rvalue(receiver) && let ty = cx.typeck_results().expr_ty(receiver) - && is_interesting(cx.tcx, ty) + && owns_allocation(cx.tcx, ty) { // FIXME: use `emit_node_lint` when `#[primary_span]` is added. cx.tcx.emit_node_span_lint( @@ -201,14 +202,14 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { // Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box, Box, // or any of the above in arbitrary many nested Box'es. -fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { +fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { if ty.is_array() { true } else if let Some(inner) = ty.boxed_ty() { inner.is_slice() || inner.is_str() || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr)) - || is_interesting(tcx, inner) + || owns_allocation(tcx, inner) } else if let Some(def) = ty.ty_adt_def() { for lang_item in [LangItem::String, LangItem::MaybeUninit] { if tcx.is_lang_item(def.did(), lang_item) { -- cgit 1.4.1-3-g733a5 From fdef65bf6e36fcecd3df71d3a630c306f7acc784 Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:05:56 -0700 Subject: Tag relevant functions with #[rustc_as_ptr] attribute --- library/alloc/src/boxed.rs | 2 ++ library/alloc/src/vec/mod.rs | 2 ++ library/core/src/cell.rs | 4 ++++ library/core/src/ffi/c_str.rs | 1 + library/core/src/mem/maybe_uninit.rs | 2 ++ library/core/src/slice/mod.rs | 2 ++ library/core/src/str/mod.rs | 2 ++ 7 files changed, 15 insertions(+) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index e4956c7c53c..425d5f2ecfb 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1499,6 +1499,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing @@ -1547,6 +1548,7 @@ impl Box { /// [`as_ptr`]: Self::as_ptr #[unstable(feature = "box_as_ptr", issue = "129090")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 07a1bd49321..990b7e8f761 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1662,6 +1662,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1724,6 +1725,7 @@ impl Vec { #[stable(feature = "vec_as_ptr", since = "1.37.0")] #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline] pub const fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 7e6c042274d..b3aaba034fe 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -587,6 +587,7 @@ impl Cell { #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() @@ -1149,6 +1150,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub fn as_ptr(&self) -> *mut T { self.value.get() @@ -2157,6 +2159,7 @@ impl UnsafeCell { #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of @@ -2303,6 +2306,7 @@ impl SyncUnsafeCell { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T` #[inline] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { self.value.get() diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 93dd351b029..f882b240e79 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -501,6 +501,7 @@ impl CStr { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b4252ef0103..5accbc3621d 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -529,6 +529,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_ptr(&self) -> *const T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. @@ -570,6 +571,7 @@ impl MaybeUninit { /// until they are, it is advisable to avoid them.) #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit_as_mut_ptr", since = "1.83.0")] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut T { // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 27e51afa800..5ab05a9f641 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -735,6 +735,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -766,6 +767,7 @@ impl [T] { #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_allow_const_fn_unstable(const_mut_refs)] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 9ef99e9dae8..fd80b33101f 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -371,6 +371,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -388,6 +389,7 @@ impl str { #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] #[rustc_const_stable(feature = "const_str_as_mut", since = "1.83.0")] #[rustc_never_returns_null_ptr] + #[cfg_attr(not(bootstrap), rustc_as_ptr)] #[must_use] #[inline(always)] pub const fn as_mut_ptr(&mut self) -> *mut u8 { -- cgit 1.4.1-3-g733a5 From 8ec94d30e514a794154ad467dd5275a78811efcc Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:30:25 -0700 Subject: Update dangling pointer tests --- compiler/rustc_lint/src/dangling.rs | 7 +-- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/cell.rs | 1 + .../dangling-pointers-from-temporaries/types.rs | 7 ++- .../types.stderr | 54 +++++++++++++++------- 5 files changed, 50 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 09fe709e845..21966758b10 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -211,13 +211,14 @@ fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr)) || owns_allocation(tcx, inner) } else if let Some(def) = ty.ty_adt_def() { - for lang_item in [LangItem::String, LangItem::MaybeUninit] { + for lang_item in [LangItem::String, LangItem::MaybeUninit, LangItem::UnsafeCell] { if tcx.is_lang_item(def.did(), lang_item) { return true; } } - tcx.get_diagnostic_name(def.did()) - .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell)) + tcx.get_diagnostic_name(def.did()).is_some_and(|name| { + matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::sync_unsafe_cell) + }) } else { false } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dde6b83c151..786be851c5d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1930,6 +1930,7 @@ symbols! { surface_async_drop_in_place, sym, sync, + sync_unsafe_cell, synthetic, t32, target, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index b3aaba034fe..e595ea56392 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2273,6 +2273,7 @@ impl, U> DispatchFromDyn> for UnsafeCell /// See [`UnsafeCell`] for details. #[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] +#[rustc_diagnostic_item = "sync_unsafe_cell"] #[rustc_pub_transparent] pub struct SyncUnsafeCell { value: UnsafeCell, diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs index 2b515d3e6d5..17c3eca89e2 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs @@ -1,6 +1,7 @@ #![deny(dangling_pointers_from_temporaries)] +#![feature(sync_unsafe_cell)] -use std::cell::Cell; +use std::cell::{Cell, SyncUnsafeCell, UnsafeCell}; use std::ffi::{CStr, CString}; use std::mem::MaybeUninit; @@ -47,6 +48,10 @@ fn main() { //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped declval::>().as_ptr(); //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + declval::>().get(); + //~^ ERROR a dangling pointer will be produced because the temporary `UnsafeCell` will be dropped + declval::>().get(); + //~^ ERROR a dangling pointer will be produced because the temporary `SyncUnsafeCell` will be dropped declval::>().as_ptr(); declval::().as_ptr(); } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr index c582a4c6540..250ed6dc9e3 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -1,5 +1,5 @@ error: a dangling pointer will be produced because the temporary `CString` will be dropped - --> $DIR/types.rs:20:26 + --> $DIR/types.rs:21:26 | LL | declval::().as_ptr(); | -------------------- ^^^^^^ this pointer will immediately be invalid @@ -15,7 +15,7 @@ LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a dangling pointer will be produced because the temporary `String` will be dropped - --> $DIR/types.rs:22:25 + --> $DIR/types.rs:23:25 | LL | declval::().as_ptr(); | ------------------- ^^^^^^ this pointer will immediately be invalid @@ -26,7 +26,7 @@ LL | declval::().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Vec` will be dropped - --> $DIR/types.rs:24:26 + --> $DIR/types.rs:25:26 | LL | declval::>().as_ptr(); | -------------------- ^^^^^^ this pointer will immediately be invalid @@ -37,7 +37,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:26:31 + --> $DIR/types.rs:27:31 | LL | declval::>().as_ptr(); | ------------------------- ^^^^^^ this pointer will immediately be invalid @@ -48,7 +48,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped - --> $DIR/types.rs:28:28 + --> $DIR/types.rs:29:28 | LL | declval::>().as_ptr(); | ---------------------- ^^^^^^ this pointer will immediately be invalid @@ -59,7 +59,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:30:27 + --> $DIR/types.rs:31:27 | LL | declval::>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -70,7 +70,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:32:28 + --> $DIR/types.rs:33:28 | LL | declval::>().as_ptr(); | ---------------------- ^^^^^^ this pointer will immediately be invalid @@ -81,7 +81,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped - --> $DIR/types.rs:34:27 + --> $DIR/types.rs:35:27 | LL | declval::<[u8; 10]>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -92,7 +92,7 @@ LL | declval::<[u8; 10]>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped - --> $DIR/types.rs:36:32 + --> $DIR/types.rs:37:32 | LL | declval::>().as_ptr(); | -------------------------- ^^^^^^ this pointer will immediately be invalid @@ -103,7 +103,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box>` will be dropped - --> $DIR/types.rs:38:31 + --> $DIR/types.rs:39:31 | LL | declval::>>().as_ptr(); | ------------------------- ^^^^^^ this pointer will immediately be invalid @@ -114,7 +114,7 @@ LL | declval::>>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box` will be dropped - --> $DIR/types.rs:40:30 + --> $DIR/types.rs:41:30 | LL | declval::>().as_ptr(); | ------------------------ ^^^^^^ this pointer will immediately be invalid @@ -125,7 +125,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Box>>>` will be dropped - --> $DIR/types.rs:42:43 + --> $DIR/types.rs:43:43 | LL | declval::>>>>().as_ptr(); | ------------------------------------- ^^^^^^ this pointer will immediately be invalid @@ -136,7 +136,7 @@ LL | declval::>>>>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Cell` will be dropped - --> $DIR/types.rs:44:27 + --> $DIR/types.rs:45:27 | LL | declval::>().as_ptr(); | --------------------- ^^^^^^ this pointer will immediately be invalid @@ -147,7 +147,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped - --> $DIR/types.rs:46:34 + --> $DIR/types.rs:47:34 | LL | declval::>().as_ptr(); | ---------------------------- ^^^^^^ this pointer will immediately be invalid @@ -158,7 +158,7 @@ LL | declval::>().as_ptr(); = help: for more information, see error: a dangling pointer will be produced because the temporary `Vec` will be dropped - --> $DIR/types.rs:48:33 + --> $DIR/types.rs:49:33 | LL | declval::>().as_ptr(); | --------------------------- ^^^^^^ this pointer will immediately be invalid @@ -168,5 +168,27 @@ LL | declval::>().as_ptr(); = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned = help: for more information, see -error: aborting due to 15 previous errors +error: a dangling pointer will be produced because the temporary `UnsafeCell` will be dropped + --> $DIR/types.rs:51:33 + | +LL | declval::>().get(); + | --------------------------- ^^^ this pointer will immediately be invalid + | | + | this `UnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see + +error: a dangling pointer will be produced because the temporary `SyncUnsafeCell` will be dropped + --> $DIR/types.rs:53:37 + | +LL | declval::>().get(); + | ------------------------------- ^^^ this pointer will immediately be invalid + | | + | this `SyncUnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | + = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: for more information, see + +error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From 24cc924af35945af57462ebeeba238ebcdf5e1ba Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:52:07 -0700 Subject: Remove as_mut_ptr symbol --- compiler/rustc_span/src/symbol.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 786be851c5d..dd969831253 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -410,7 +410,6 @@ symbols! { arm, arm_target_feature, array, - as_mut_ptr, as_ptr, as_ref, as_str, -- cgit 1.4.1-3-g733a5 From 37ea2028beed52aa8cc2406b75f59a98d02ed457 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:12:40 +0100 Subject: ci: use free runner in dist-i686-msvc --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 340dfd67b7d..80ae62d7ac0 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -465,7 +465,7 @@ auto: SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift - <<: *job-windows-8c + <<: *job-windows - image: dist-aarch64-msvc env: -- cgit 1.4.1-3-g733a5 From 09c268417f596520de48dea387bdbf12a08da29c Mon Sep 17 00:00:00 2001 From: maxcabrajac Date: Mon, 18 Nov 2024 15:40:34 -0300 Subject: Add Visitor::visit_fn_decl --- compiler/rustc_ast/src/visit.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3500c215376..03fd3c27950 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -299,6 +299,9 @@ pub trait Visitor<'ast>: Sized { fn visit_coroutine_kind(&mut self, _coroutine_kind: &'ast CoroutineKind) -> Self::Result { Self::Result::output() } + fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result { + walk_fn_decl(self, fn_decl) + } } pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { @@ -518,7 +521,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { let BareFnTy { safety: _, ext: _, generic_params, decl, decl_span: _ } = &**function_declaration; walk_list!(visitor, visit_generic_param, generic_params); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); } TyKind::Path(maybe_qself, path) => { try_visit!(walk_qself(visitor, maybe_qself)); @@ -846,13 +849,13 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu // Identifier and visibility are visited as a part of the item. try_visit!(visitor.visit_fn_header(header)); try_visit!(visitor.visit_generics(generics)); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); visit_opt!(visitor, visit_block, body); } FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); - try_visit!(walk_fn_decl(visitor, decl)); + try_visit!(visitor.visit_fn_decl(decl)); try_visit!(visitor.visit_expr(body)); } } -- cgit 1.4.1-3-g733a5 From e65deb5ee1f0273ef357f181c843293a752f29bd Mon Sep 17 00:00:00 2001 From: maxcabrajac Date: Mon, 18 Nov 2024 15:43:35 -0300 Subject: Add Visitor::visit_qself --- compiler/rustc_ast/src/visit.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 03fd3c27950..c121e7711ee 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -302,6 +302,9 @@ pub trait Visitor<'ast>: Sized { fn visit_fn_decl(&mut self, fn_decl: &'ast FnDecl) -> Self::Result { walk_fn_decl(self, fn_decl) } + fn visit_qself(&mut self, qs: &'ast Option>) -> Self::Result { + walk_qself(self, qs) + } } pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { @@ -437,13 +440,13 @@ impl WalkItemKind for ItemKind { body, from_glob: _, }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { @@ -524,7 +527,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { try_visit!(visitor.visit_fn_decl(decl)); } TyKind::Path(maybe_qself, path) => { - try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); } TyKind::Pat(ty, pat) => { @@ -655,16 +658,16 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res let Pat { id, kind, span: _, tokens: _ } = pattern; match kind { PatKind::TupleStruct(opt_qself, path, elems) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat, elems); } PatKind::Path(opt_qself, path) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)) } PatKind::Struct(opt_qself, path, fields, _rest) => { - try_visit!(walk_qself(visitor, opt_qself)); + try_visit!(visitor.visit_qself(opt_qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_pat_field, fields); } @@ -905,13 +908,13 @@ impl WalkItemKind for AssocItemKind { body, from_glob: _, }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); visit_opt!(visitor, visit_ident, rename); visit_opt!(visitor, visit_block, body); } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(prefix, id)); if let Some(suffixes) = suffixes { for (ident, rename) in suffixes { @@ -1026,7 +1029,7 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>( visitor: &mut V, InlineAsmSym { id, qself, path }: &'a InlineAsmSym, ) -> V::Result { - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); visitor.visit_path(path, *id) } @@ -1058,7 +1061,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Struct(se) => { let StructExpr { qself, path, fields, rest } = &**se; - try_visit!(walk_qself(visitor, qself)); + try_visit!(visitor.visit_qself(qself)); try_visit!(visitor.visit_path(path, *id)); walk_list!(visitor, visit_expr_field, fields); match rest { @@ -1167,7 +1170,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Underscore => {} ExprKind::Path(maybe_qself, path) => { - try_visit!(walk_qself(visitor, maybe_qself)); + try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); } ExprKind::Break(opt_label, opt_expr) => { -- cgit 1.4.1-3-g733a5 From f6340f13bb05b0606675e59f10e8c5ec7f2cd7be Mon Sep 17 00:00:00 2001 From: maxcabrajac Date: Mon, 18 Nov 2024 15:49:09 -0300 Subject: Add MutVisitor::visit_fn_ret_ty --- compiler/rustc_ast/src/mut_visit.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a09aa9ee665..811cb0be9f9 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -330,6 +330,10 @@ pub trait MutVisitor: Sized { fn visit_capture_by(&mut self, capture_by: &mut CaptureBy) { walk_capture_by(self, capture_by) } + + fn visit_fn_ret_ty(&mut self, fn_ret_ty: &mut FnRetTy) { + walk_fn_ret_ty(self, fn_ret_ty) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -609,7 +613,7 @@ fn walk_angle_bracketed_parameter_data(vis: &mut T, data: &mut An fn walk_parenthesized_parameter_data(vis: &mut T, args: &mut ParenthesizedArgs) { let ParenthesizedArgs { inputs, output, span, inputs_span } = args; visit_thin_vec(inputs, |input| vis.visit_ty(input)); - walk_fn_ret_ty(vis, output); + vis.visit_fn_ret_ty(output); vis.visit_span(span); vis.visit_span(inputs_span); } @@ -911,7 +915,7 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { fn walk_fn_decl(vis: &mut T, decl: &mut P) { let FnDecl { inputs, output } = decl.deref_mut(); inputs.flat_map_in_place(|param| vis.flat_map_param(param)); - walk_fn_ret_ty(vis, output); + vis.visit_fn_ret_ty(output); } fn walk_fn_ret_ty(vis: &mut T, fn_ret_ty: &mut FnRetTy) { -- cgit 1.4.1-3-g733a5 From 6f8fe7929aa3c7131180442dc7d90ea1be831204 Mon Sep 17 00:00:00 2001 From: omni Date: Mon, 18 Nov 2024 20:35:38 +0000 Subject: Make rustc --explain busybox less compatible busybox less does not support the -r flag and less(1) says: USE OF THE -r OPTION IS NOT RECOMMENDED. --- compiler/rustc_driver_impl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b6f7abed6f3..8dd043be6ad 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -577,7 +577,7 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) { let mut cmd = Command::new(&pager_name); // FIXME: find if other pagers accept color options let mut print_formatted = if pager_name == "less" { - cmd.arg("-r"); + cmd.arg("-R"); true } else { ["bat", "catbat", "delta"].iter().any(|v| *v == pager_name) -- cgit 1.4.1-3-g733a5 From 0270580bc5d0c507b61bdf5cacce67b78fde207a Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:09:13 +0100 Subject: CI: use free runner in dist-aarch64-msvc --- src/ci/github-actions/jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 340dfd67b7d..eea97e98cc2 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -477,7 +477,7 @@ auto: --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-8c + <<: *job-windows - image: dist-i686-mingw env: -- cgit 1.4.1-3-g733a5 From 7bffa310426ebcc01cfb1756ae1883118a32366b Mon Sep 17 00:00:00 2001 From: "Panagiotis \"Ivory\" Vasilopoulos" Date: Mon, 18 Nov 2024 18:42:00 +0100 Subject: Mention std::fs::remove_dir_all in std::fs::remove_dir --- library/std/src/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 76fdb1a4ffd..555e8804eab 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2738,6 +2738,10 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// Removes an empty directory. /// +/// If you want to remove a directory that is not empty, as well as all +/// of its contents recursively, consider using [`remove_dir_all`] +/// instead. +/// /// # Platform-specific behavior /// /// This function currently corresponds to the `rmdir` function on Unix -- cgit 1.4.1-3-g733a5 From df29f9b0c3a2277c2eb2de2e0bf4f4b3329dbd00 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Nov 2024 14:48:48 +1100 Subject: Improve `fake_ident_or_unknown_prefix`. - Rename it as `invalid_ident_or_prefix`, which matches the possible outputs (`InvalidIdent` or `InvalidPrefix`). - Use the local wrapper for `is_xid_continue`, for consistency. - Make it clear what `\u{200d}` means. --- compiler/rustc_lexer/src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index f9f2a14dbd2..7f221098364 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -468,7 +468,7 @@ impl Cursor<'_> { Literal { kind, suffix_start } } // Identifier starting with an emoji. Only lexed for graceful error recovery. - c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(), + c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident_or_prefix(), _ => Unknown, }; let res = Token::new(token_kind, self.pos_within_token()); @@ -552,17 +552,16 @@ impl Cursor<'_> { // we see a prefix here, it is definitely an unknown prefix. match self.first() { '#' | '"' | '\'' => UnknownPrefix, - c if !c.is_ascii() && c.is_emoji_char() => self.fake_ident_or_unknown_prefix(), + c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident_or_prefix(), _ => Ident, } } - fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind { + fn invalid_ident_or_prefix(&mut self) -> TokenKind { // Start is already eaten, eat the rest of identifier. self.eat_while(|c| { - unicode_xid::UnicodeXID::is_xid_continue(c) - || (!c.is_ascii() && c.is_emoji_char()) - || c == '\u{200d}' + const ZERO_WIDTH_JOINER: char = '\u{200d}'; + is_id_continue(c) || (!c.is_ascii() && c.is_emoji_char()) || c == ZERO_WIDTH_JOINER }); // Known prefixes must have been handled earlier. So if // we see a prefix here, it is definitely an unknown prefix. -- cgit 1.4.1-3-g733a5 From 2c7c3697dbaac3e0599aa0e7cd3581822caec17b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Nov 2024 15:11:18 +1100 Subject: Improve `TokenKind` comments. - Improve wording. - Use backticks consistently for examples. --- compiler/rustc_lexer/src/lib.rs | 80 ++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 7f221098364..c01dad810c4 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -57,11 +57,10 @@ impl Token { /// Enum representing common lexeme types. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TokenKind { - // Multi-char tokens: - /// "// comment" + /// A line comment, e.g. `// comment`. LineComment { doc_style: Option }, - /// `/* block comment */` + /// A block comment, e.g. `/* block comment */`. /// /// Block comments can be recursive, so a sequence like `/* /* */` /// will not be considered terminated and will result in a parsing error. @@ -70,18 +69,17 @@ pub enum TokenKind { /// Any whitespace character sequence. Whitespace, - /// "ident" or "continue" - /// - /// At this step, keywords are also considered identifiers. + /// An identifier or keyword, e.g. `ident` or `continue`. Ident, - /// Like the above, but containing invalid unicode codepoints. + /// An identifier that is invalid because it contains emoji. InvalidIdent, - /// "r#ident" + /// A raw identifier, e.g. "r#ident". RawIdent, - /// An unknown prefix, like `foo#`, `foo'`, `foo"`. + /// An unknown literal prefix, like `foo#`, `foo'`, `foo"`. Excludes + /// literal prefixes that contain emoji, which are considered "invalid". /// /// Note that only the /// prefix (`foo`) is included in the token, not the separator (which is @@ -93,11 +91,12 @@ pub enum TokenKind { /// An unknown prefix in a lifetime, like `'foo#`. /// - /// Note that like above, only the `'` and prefix are included in the token + /// Like `UnknownPrefix`, only the `'` and prefix are included in the token /// and not the separator. UnknownPrefixLifetime, - /// `'r#lt`, which in edition < 2021 is split into several tokens: `'r # lt`. + /// A raw lifetime, e.g. `'r#foo`. In edition < 2021 it will be split into + /// several tokens: `'r` and `#` and `foo`. RawLifetime, /// Similar to the above, but *always* an error on every edition. This is used @@ -110,70 +109,69 @@ pub enum TokenKind { /// Split into the component tokens on older editions. GuardedStrPrefix, - /// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid + /// Literals, e.g. `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid /// suffix, but may be present here on string and float literals. Users of /// this type will need to check for and reject that case. /// /// See [LiteralKind] for more details. Literal { kind: LiteralKind, suffix_start: u32 }, - /// "'a" + /// A lifetime, e.g. `'a`. Lifetime { starts_with_number: bool }, - // One-char tokens: - /// ";" + /// `;` Semi, - /// "," + /// `,` Comma, - /// "." + /// `.` Dot, - /// "(" + /// `(` OpenParen, - /// ")" + /// `)` CloseParen, - /// "{" + /// `{` OpenBrace, - /// "}" + /// `}` CloseBrace, - /// "[" + /// `[` OpenBracket, - /// "]" + /// `]` CloseBracket, - /// "@" + /// `@` At, - /// "#" + /// `#` Pound, - /// "~" + /// `~` Tilde, - /// "?" + /// `?` Question, - /// ":" + /// `:` Colon, - /// "$" + /// `$` Dollar, - /// "=" + /// `=` Eq, - /// "!" + /// `!` Bang, - /// "<" + /// `<` Lt, - /// ">" + /// `>` Gt, - /// "-" + /// `-` Minus, - /// "&" + /// `&` And, - /// "|" + /// `|` Or, - /// "+" + /// `+` Plus, - /// "*" + /// `*` Star, - /// "/" + /// `/` Slash, - /// "^" + /// `^` Caret, - /// "%" + /// `%` Percent, /// Unknown token, not expected by the lexer, e.g. "№" -- cgit 1.4.1-3-g733a5 From e9a0c3c98c5640070e15a3cb38860a7268c1dca2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Nov 2024 15:55:34 +1100 Subject: Remove `TokenKind::InvalidPrefix`. It was added in #123752 to handle some cases involving emoji, but it isn't necessary because it's always treated the same as `TokenKind::InvalidIdent`. This commit removes it, which makes things a little simpler. --- compiler/rustc_lexer/src/lib.rs | 21 ++++++++------------- compiler/rustc_parse/src/lexer/mod.rs | 5 ++--- src/librustdoc/html/highlight.rs | 7 +++---- .../rust-analyzer/crates/parser/src/lexed_str.rs | 2 +- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c01dad810c4..bcb103957ba 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -99,10 +99,6 @@ pub enum TokenKind { /// several tokens: `'r` and `#` and `foo`. RawLifetime, - /// Similar to the above, but *always* an error on every edition. This is used - /// for emoji identifier recovery, as those are not meant to be ever accepted. - InvalidPrefix, - /// Guarded string literal prefix: `#"` or `##`. /// /// Used for reserving "guarded strings" (RFC 3598) in edition 2024. @@ -466,7 +462,7 @@ impl Cursor<'_> { Literal { kind, suffix_start } } // Identifier starting with an emoji. Only lexed for graceful error recovery. - c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident_or_prefix(), + c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), _ => Unknown, }; let res = Token::new(token_kind, self.pos_within_token()); @@ -550,23 +546,22 @@ impl Cursor<'_> { // we see a prefix here, it is definitely an unknown prefix. match self.first() { '#' | '"' | '\'' => UnknownPrefix, - c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident_or_prefix(), + c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), _ => Ident, } } - fn invalid_ident_or_prefix(&mut self) -> TokenKind { + fn invalid_ident(&mut self) -> TokenKind { // Start is already eaten, eat the rest of identifier. self.eat_while(|c| { const ZERO_WIDTH_JOINER: char = '\u{200d}'; is_id_continue(c) || (!c.is_ascii() && c.is_emoji_char()) || c == ZERO_WIDTH_JOINER }); - // Known prefixes must have been handled earlier. So if - // we see a prefix here, it is definitely an unknown prefix. - match self.first() { - '#' | '"' | '\'' => InvalidPrefix, - _ => InvalidIdent, - } + // An invalid identifier followed by '#' or '"' or '\'' could be + // interpreted as an invalid literal prefix. We don't bother doing that + // because the treatment of invalid identifiers and invalid prefixes + // would be the same. + InvalidIdent } fn c_or_byte_string( diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 226de65445c..5023e83bd67 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -213,7 +213,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { let ident = Symbol::intern(lifetime_name); token::Lifetime(ident, IdentIsRaw::No) } - rustc_lexer::TokenKind::InvalidIdent | rustc_lexer::TokenKind::InvalidPrefix + rustc_lexer::TokenKind::InvalidIdent // Do not recover an identifier with emoji if the codepoint is a confusable // with a recoverable substitution token, like `➖`. if !UNICODE_ARRAY.iter().any(|&(c, _, _)| { @@ -359,8 +359,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), rustc_lexer::TokenKind::Unknown - | rustc_lexer::TokenKind::InvalidIdent - | rustc_lexer::TokenKind::InvalidPrefix => { + | rustc_lexer::TokenKind::InvalidIdent => { // Don't emit diagnostics for sequences of the same invalid token if swallow_next_invalid > 0 { swallow_next_invalid -= 1; diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 4def80764ea..29f6f92a6b2 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -861,10 +861,9 @@ impl<'src> Classifier<'src> { }, Some(c) => c, }, - TokenKind::RawIdent - | TokenKind::UnknownPrefix - | TokenKind::InvalidPrefix - | TokenKind::InvalidIdent => Class::Ident(self.new_span(before, text)), + TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => { + Class::Ident(self.new_span(before, text)) + } TokenKind::Lifetime { .. } | TokenKind::RawLifetime | TokenKind::UnknownPrefixLifetime => Class::Lifetime, diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 3c0eb1b42a6..c97596d5097 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -183,7 +183,7 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::Ident => { SyntaxKind::from_keyword(token_text, self.edition).unwrap_or(IDENT) } - rustc_lexer::TokenKind::InvalidPrefix | rustc_lexer::TokenKind::InvalidIdent => { + rustc_lexer::TokenKind::InvalidIdent => { err = "Ident contains invalid characters"; IDENT } -- cgit 1.4.1-3-g733a5 From 38f0c099b2e684ea689633eb424d8737a1063a5e Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 19 Nov 2024 18:48:02 +0800 Subject: Default-enable `llvm_tools_enabled` when no `config.toml` is present --- src/bootstrap/src/core/config/config.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 95b1303fa71..e706aba977b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1255,6 +1255,10 @@ impl Config { }, out: PathBuf::from("build"), + // This is needed by codegen_ssa on macOS to ship `llvm-objcopy` aliased to + // `rust-objcopy` to workaround bad `strip`s on macOS. + llvm_tools_enabled: true, + ..Default::default() } } -- cgit 1.4.1-3-g733a5 From fcfb782a7582fc5f2264c2bcb67e6ffe6ea4a0e2 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 19 Nov 2024 19:04:45 +0800 Subject: Register change info --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1d05f94e3be..7f62ffb20db 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -300,4 +300,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "`download-rustc='if-unchanged'` is now a default option for library profile.", }, + ChangeInfo { + change_id: 133207, + severity: ChangeSeverity::Info, + summary: "`rust.llvm-tools` is now enabled by default when no `config.toml` is provided.", + }, ]; -- cgit 1.4.1-3-g733a5 From 4b5c88301bcc20de9fa58b7390d78d596f7d7223 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 19 Nov 2024 20:00:58 +0800 Subject: Explicitly disable llvm tools for cranelift --- compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 2f13b0b9cb8..5b3f2a91207 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -38,6 +38,11 @@ local-rebuild = true codegen-backends = ["cranelift"] deny-warnings = false verbose-tests = false +# The cg_clif sysroot doesn't contain llvm tools and unless llvm_tools is +# disabled bootstrap will crash trying to copy llvm tools for the bootstrap +# compiler. +llvm_tools = false + EOF popd -- cgit 1.4.1-3-g733a5 From 616013fc49bc6cb7a627c64114bfdd9784ae6d0c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 19 Nov 2024 07:56:34 -0800 Subject: Correct the tier listing of `wasm32-wasip2` This target is tier 2, not tier 3, and I forgot to update this. Closes #133206 --- src/doc/rustc/src/platform-support/wasm32-wasip2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md index bb2348b201e..40049ecfa5f 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md @@ -1,6 +1,6 @@ # `wasm32-wasip2` -**Tier: 3** +**Tier: 2** The `wasm32-wasip2` target is a new and still (as of January 2024) an experimental target. This target is an extension to `wasm32-wasip1` target, -- cgit 1.4.1-3-g733a5 From 01fd384d5800deb1e96b0d8921e82317e9fcdb8b Mon Sep 17 00:00:00 2001 From: gavincrawford <94875769+gavincrawford@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:32:13 -0700 Subject: Correct comments concerning updated dangling pointer lint --- compiler/rustc_lint/src/dangling.rs | 13 +++++-------- compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/cell.rs | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 21966758b10..e3e51ba263d 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -43,13 +43,10 @@ declare_lint! { } /// FIXME: false negatives (i.e. the lint is not emitted when it should be) -/// 1. Method calls that are not checked for: -/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`] -/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`] -/// 2. Ways to get a temporary that are not recognized: +/// 1. Ways to get a temporary that are not recognized: /// - `owning_temporary.field` /// - `owning_temporary[index]` -/// 3. No checks for ref-to-ptr conversions: +/// 2. No checks for ref-to-ptr conversions: /// - `&raw [mut] temporary` /// - `&temporary as *(const|mut) _` /// - `ptr::from_ref(&temporary)` and friends @@ -200,8 +197,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { } } -// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box, Box, -// or any of the above in arbitrary many nested Box'es. +// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box, Box, UnsafeCell, +// SyncUnsafeCell, or any of the above in arbitrary many nested Box'es. fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { if ty.is_array() { true @@ -217,7 +214,7 @@ fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { } } tcx.get_diagnostic_name(def.did()).is_some_and(|name| { - matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::sync_unsafe_cell) + matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::SyncUnsafeCell) }) } else { false diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dd969831253..a7c43a20840 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -316,6 +316,7 @@ symbols! { SubdiagMessage, Subdiagnostic, Sync, + SyncUnsafeCell, T, Target, ToOwned, @@ -1929,7 +1930,6 @@ symbols! { surface_async_drop_in_place, sym, sync, - sync_unsafe_cell, synthetic, t32, target, diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e595ea56392..20904c9bc76 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2273,7 +2273,7 @@ impl, U> DispatchFromDyn> for UnsafeCell /// See [`UnsafeCell`] for details. #[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] -#[rustc_diagnostic_item = "sync_unsafe_cell"] +#[rustc_diagnostic_item = "SyncUnsafeCell"] #[rustc_pub_transparent] pub struct SyncUnsafeCell { value: UnsafeCell, -- cgit 1.4.1-3-g733a5 From 948cec0fad6d87f7f5993517f913aa0454b78674 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 16:13:55 +0100 Subject: move `fn is_item_raw` to `TypingEnv` --- compiler/rustc_borrowck/src/type_check/mod.rs | 3 ++- compiler/rustc_codegen_cranelift/src/base.rs | 4 ++-- compiler/rustc_codegen_cranelift/src/common.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/type_.rs | 6 +++--- .../rustc_const_eval/src/check_consts/resolver.rs | 5 +---- compiler/rustc_const_eval/src/const_eval/machine.rs | 2 +- .../rustc_const_eval/src/interpret/eval_context.rs | 2 +- compiler/rustc_const_eval/src/interpret/intern.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- compiler/rustc_const_eval/src/interpret/validity.rs | 8 +++++--- compiler/rustc_hir_analysis/src/check/check.rs | 10 +++++----- compiler/rustc_hir_analysis/src/check/intrinsicck.rs | 17 +++++++++++------ compiler/rustc_hir_analysis/src/coherence/orphan.rs | 2 +- compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 8 ++++++-- compiler/rustc_lint/src/builtin.rs | 14 ++++++-------- compiler/rustc_lint/src/drop_forget_useless.rs | 2 +- compiler/rustc_lint/src/reference_casting.rs | 2 +- compiler/rustc_lint/src/types.rs | 6 +++--- compiler/rustc_middle/src/mir/interpret/mod.rs | 6 +++--- compiler/rustc_middle/src/query/mod.rs | 8 ++++---- compiler/rustc_middle/src/ty/layout.rs | 14 +++++++------- compiler/rustc_middle/src/ty/util.rs | 20 ++++++++++++-------- .../rustc_mir_build/src/build/expr/as_operand.rs | 6 ++---- compiler/rustc_mir_build/src/build/mod.rs | 4 ++++ compiler/rustc_mir_build/src/check_unsafety.rs | 17 ++++++++--------- .../rustc_mir_build/src/thir/pattern/check_match.rs | 12 +++++++++++- .../rustc_mir_build/src/thir/pattern/const_to_pat.rs | 6 +++--- compiler/rustc_mir_transform/src/check_alignment.rs | 10 +++++----- compiler/rustc_mir_transform/src/copy_prop.rs | 4 ++-- .../rustc_mir_transform/src/deduce_param_attrs.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 19 +++++++++---------- compiler/rustc_mir_transform/src/inline.rs | 5 +---- .../rustc_mir_transform/src/known_panics_lint.rs | 2 +- compiler/rustc_mir_transform/src/ref_prop.rs | 4 ++-- compiler/rustc_mir_transform/src/ssa.rs | 6 +++--- compiler/rustc_mir_transform/src/validate.rs | 10 +++++----- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_trait_selection/src/infer.rs | 4 +++- compiler/rustc_ty_utils/src/abi.rs | 2 +- compiler/rustc_ty_utils/src/common_traits.rs | 17 ++++++++--------- compiler/rustc_ty_utils/src/layout.rs | 14 +++++--------- compiler/rustc_ty_utils/src/needs_drop.rs | 2 +- src/librustdoc/clean/auto_trait.rs | 2 +- .../clippy/clippy_lints/src/casts/ptr_as_ptr.rs | 2 +- src/tools/clippy/clippy_lints/src/dereference.rs | 2 +- .../clippy/clippy_lints/src/functions/must_use.rs | 2 +- src/tools/clippy/clippy_lints/src/let_if_seq.rs | 2 +- .../clippy_lints/src/methods/manual_inspect.rs | 6 +++--- src/tools/clippy/clippy_lints/src/mut_mut.rs | 2 +- .../clippy_lints/src/needless_pass_by_value.rs | 2 +- src/tools/clippy/clippy_lints/src/question_mark.rs | 2 +- .../src/transmute/transmute_ptr_to_ptr.rs | 2 +- .../src/transmute/transmute_undefined_repr.rs | 4 ++-- .../clippy_lints/src/types/redundant_allocation.rs | 2 +- src/tools/clippy/clippy_lints/src/types/vec_box.rs | 2 +- .../clippy_lints/src/unnecessary_box_returns.rs | 2 +- src/tools/clippy/clippy_utils/src/ty.rs | 2 +- .../miri/src/borrow_tracker/stacked_borrows/mod.rs | 7 +++---- .../miri/src/borrow_tracker/tree_borrows/mod.rs | 11 +++++------ 60 files changed, 181 insertions(+), 168 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 58a23b9e558..c6b34d5bf1d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1727,7 +1727,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. let erased_ty = tcx.erase_regions(ty); - if !erased_ty.is_sized(tcx, self.infcx.param_env) { + // FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here. + if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 1b91d251bfd..77ee9773940 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::InlineAsmMacro; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::FnAbiOf; +use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; use rustc_middle::ty::print::with_no_trimmed_paths; use crate::constant::ConstantCx; @@ -841,7 +841,7 @@ fn codegen_stmt<'tcx>( lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } Rvalue::NullaryOp(ref null_op, ty) => { - assert!(lval.layout().ty.is_sized(fx.tcx, ty::ParamEnv::reveal_all())); + assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index add081bc795..c663fa32965 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -103,7 +103,7 @@ fn clif_pair_type_from_ty<'tcx>( /// Is a pointer to this type a wide ptr? pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - if ty.is_sized(tcx, ty::ParamEnv::reveal_all()) { + if ty.is_sized(tcx, ty::TypingEnv::fully_monomorphized()) { return false; } diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 3810c609fd4..6292d321f6b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -78,15 +78,15 @@ pub trait DerivedTypeCodegenMethods<'tcx>: } fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all()) + ty.is_sized(self.tcx(), self.typing_env()) } fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all()) + ty.is_freeze(self.tcx(), self.typing_env()) } fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { - if ty.is_sized(self.tcx(), self.param_env()) { + if ty.is_sized(self.tcx(), self.typing_env()) { return false; } diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 03624a2ce50..0f9a460ca1b 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -120,10 +120,7 @@ where /// /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool { - !place - .ty(self.ccx.body, self.ccx.tcx) - .ty - .is_freeze(self.ccx.tcx, self.ccx.typing_env.param_env) + !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.typing_env) } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 19c3195aaa4..347b1557d87 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -667,7 +667,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { .is_some_and(|p| !p.immutable()) { // That next check is expensive, that's why we have all the guards above. - let is_immutable = ty.is_freeze(*ecx.tcx, ecx.param_env); + let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env()); let place = ecx.ref_to_mplace(val)?; let new_place = if is_immutable { place.map_provenance(CtfeProvenance::as_immutable) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 4f413c84615..31ce1600ce7 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -250,7 +250,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline] pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(*self.tcx, self.param_env) + ty.is_freeze(*self.tcx, self.typing_env()) } pub fn load_mir( diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 7a1b92601a4..2d695688ae5 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -165,7 +165,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval InternKind::Static(Mutability::Not) => { ( // Outermost allocation is mutable if `!Freeze`. - if ret.layout.ty.is_freeze(*ecx.tcx, ecx.param_env) { + if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env()) { Mutability::Not } else { Mutability::Mut diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 07566e9fda2..9bae9c4b310 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -860,7 +860,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // # Global allocations if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env()); - let mutbl = global_alloc.mutability(*self.tcx, self.param_env); + let mutbl = global_alloc.mutability(*self.tcx, self.typing_env()); let kind = match global_alloc { GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 005b430bc8a..9ff24a01689 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -619,7 +619,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; // Determine what it actually points to. let alloc_actual_mutbl = - global_alloc.mutability(*self.ecx.tcx, self.ecx.param_env); + global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env()); // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not @@ -848,7 +848,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { let tcx = *self.ecx.tcx; // Everything must be already interned. - let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.param_env); + let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.typing_env()); if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) { assert_eq!(alloc.mutability, mutbl); } @@ -1085,7 +1085,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, ) -> InterpResult<'tcx> { // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) { + if !val.layout.is_zst() + && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env()) + { if !self.in_mutable_memory(val) { throw_validation_failure!(self.path, UnsafeCellInImmutable); } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index cf8c81c0b08..aa9d303cacb 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -90,24 +90,24 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b fn allowed_union_field<'tcx>( ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> bool { // We don't just accept all !needs_drop fields, due to semver concerns. match ty.kind() { ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) ty::Tuple(tys) => { // allow tuples of allowed types - tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env)) + tys.iter().all(|ty| allowed_union_field(ty, tcx, typing_env)) } ty::Array(elem, _len) => { // Like `Copy`, we do *not* special-case length 0. - allowed_union_field(*elem, tcx, param_env) + allowed_union_field(*elem, tcx, typing_env) } _ => { // Fallback case: allow `ManuallyDrop` and things that are `Copy`, // also no need to report an error if the type is unresolved. ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) - || ty.is_copy_modulo_regions(tcx, param_env) + || ty.is_copy_modulo_regions(tcx, typing_env) || ty.references_error() } } @@ -121,7 +121,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b continue; }; - if !allowed_union_field(field_ty, tcx, typing_env.param_env) { + if !allowed_union_field(field_ty, tcx, typing_env) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { // We are currently checking the type this field came from, so it must be local. Some(Node::Field(field)) => (field.span, field.ty.span), diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index e95669c9d40..dfddf93a5c2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -15,7 +15,7 @@ use rustc_target::asm::{ pub struct InlineAsmCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, get_operand_ty: Box) -> Ty<'tcx> + 'a>, } @@ -23,24 +23,29 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { InlineAsmCtxt { tcx, - param_env: ty::ParamEnv::empty(), + typing_env: ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: ty::ParamEnv::empty(), + }, get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")), } } + // FIXME(#132279): This likely causes us to incorrectly handle opaque types in their + // defining scope. pub fn new_in_fn( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a, ) -> Self { - InlineAsmCtxt { tcx, param_env, get_operand_ty: Box::new(get_operand_ty) } + InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) } } // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { // Type still may have region variables, but `Sized` does not depend // on those, so just erase them before querying. - if ty.is_sized(self.tcx, self.param_env) { + if ty.is_sized(self.tcx, self.typing_env) { return true; } if let ty::Foreign(..) = ty.kind() { @@ -171,7 +176,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !ty.is_copy_modulo_regions(self.tcx, self.param_env) { + if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) { let msg = "arguments for inline assembly must be copyable"; self.tcx .dcx() diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 8a1a887766c..eca85c22a40 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -172,7 +172,7 @@ pub(crate) fn orphan_check_impl( // impl AutoTrait for T {} // impl AutoTrait for T {} ty::Param(..) => ( - if self_ty.is_sized(tcx, tcx.param_env(impl_def_id)) { + if self_ty.is_sized(tcx, ty::TypingEnv::non_body_analysis(tcx, impl_def_id)) { LocalImpl::Allow } else { LocalImpl::Disallow { problematic_kind: "generic type" } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 59bef8315d8..2a00530c434 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -228,7 +228,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { } fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool { - ty.is_copy_modulo_regions(self.0.tcx, self.0.param_env) + ty.is_copy_modulo_regions(self.0.tcx, self.0.typing_env()) } fn body_owner_def_id(&self) -> LocalDefId { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 50d1322eba6..961526831fb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -105,8 +105,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.erase_regions(ty) } }; - InlineAsmCtxt::new_in_fn(self.tcx, self.param_env, get_operand_ty) - .check_asm(asm, enclosing_id); + InlineAsmCtxt::new_in_fn( + self.tcx, + self.infcx.typing_env(self.param_env), + get_operand_ty, + ) + .check_asm(asm, enclosing_id); } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index f6366ec3b80..bda982a3675 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -32,7 +32,7 @@ use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; @@ -586,10 +586,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { return; } } - if ty.is_copy_modulo_regions(cx.tcx, cx.param_env) { + if ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) { return; } - if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.param_env) { + if type_implements_negative_copy_modulo_regions(cx.tcx, ty, cx.typing_env()) { return; } if def.is_variant_list_non_exhaustive() @@ -637,8 +637,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { fn type_implements_negative_copy_modulo_regions<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> bool { + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]); let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative }; let obligation = traits::Obligation { @@ -647,10 +648,7 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( recursion_depth: 0, predicate: pred.upcast(tcx), }; - - tcx.infer_ctxt() - .build(TypingMode::non_body_analysis()) - .predicate_must_hold_modulo_regions(&obligation) + infcx.predicate_must_hold_modulo_regions(&obligation) } declare_lint! { diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 364c6fd488a..8fe86738658 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id) { let arg_ty = cx.typeck_results().expr_ty(arg); - let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let let_underscore_ignore_sugg = || { if let Some((_, node)) = cx.tcx.hir().parent_iter(expr.hir_id).nth(0) diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 45d97403d60..7c6656f91c9 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -168,7 +168,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>( // Except on the presence of non concrete skeleton types (ie generics) // since there is no way to make it safe for arbitrary types. let inner_ty_has_interior_mutability = - !inner_ty.is_freeze(cx.tcx, cx.param_env) && inner_ty.has_concrete_skeleton(); + !inner_ty.is_freeze(cx.tcx, cx.typing_env()) && inner_ty.has_concrete_skeleton(); (!need_check_freeze || !inner_ty_has_interior_mutability) .then_some(inner_ty_has_interior_mutability) } else { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 2e6cb993842..b1d7d4ab689 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -292,7 +292,7 @@ fn lint_wide_pointer<'tcx>( _ => return None, }; - (!ty.is_sized(cx.tcx, cx.param_env)) + (!ty.is_sized(cx.tcx, cx.typing_env())) .then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))) }; @@ -904,7 +904,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if let Some(boxed) = ty.boxed_ty() && matches!(self.mode, CItemKind::Definition) { - if boxed.is_sized(tcx, self.cx.param_env) { + if boxed.is_sized(tcx, self.cx.typing_env()) { return FfiSafe; } else { return FfiUnsafe { @@ -1069,7 +1069,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::RawPtr(ty, _) | ty::Ref(_, ty, _) if { matches!(self.mode, CItemKind::Definition) - && ty.is_sized(self.cx.tcx, self.cx.param_env) + && ty.is_sized(self.cx.tcx, self.cx.typing_env()) } => { FfiSafe diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c4b0e6e39cc..8d73c9e76de 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -46,7 +46,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use crate::ty::{self, Instance, Ty, TyCtxt}; /// Uniquely identifies one of the following: /// - A constant @@ -312,7 +312,7 @@ impl<'tcx> GlobalAlloc<'tcx> { } } - pub fn mutability(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Mutability { + pub fn mutability(&self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Mutability { // Let's see what kind of memory we are. match self { GlobalAlloc::Static(did) => { @@ -334,7 +334,7 @@ impl<'tcx> GlobalAlloc<'tcx> { .type_of(did) .no_bound_vars() .expect("statics should not have generic parameters") - .is_freeze(tcx, param_env) => + .is_freeze(tcx, typing_env) => { Mutability::Mut } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 684d5b6c2a7..b8291e8a352 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1390,19 +1390,19 @@ rustc_queries! { /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, /// `ty.is_copy()`, etc, since that will prune the environment where possible. - query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Copy`", env.value } } /// Query backing `Ty::is_sized`. - query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } } /// Query backing `Ty::is_freeze`. - query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_freeze_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is freeze", env.value } } /// Query backing `Ty::is_unpin`. - query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + query is_unpin_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Unpin`", env.value } } /// Query backing `Ty::needs_drop`. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8625a8dcb2a..fc29b438d3a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1002,12 +1002,12 @@ where // attributes in LLVM have compile-time cost even in unoptimized builds). let optimize = tcx.sess.opts.optimize != OptLevel::No; let kind = match mt { - hir::Mutability::Not => PointerKind::SharedRef { - frozen: optimize && ty.is_freeze(tcx, typing_env.param_env), - }, - hir::Mutability::Mut => PointerKind::MutableRef { - unpin: optimize && ty.is_unpin(tcx, typing_env.param_env), - }, + hir::Mutability::Not => { + PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) } + } + hir::Mutability::Mut => { + PointerKind::MutableRef { unpin: optimize && ty.is_unpin(tcx, typing_env) } + } }; tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo { @@ -1100,7 +1100,7 @@ where debug_assert!(pointee.safe.is_none()); let optimize = tcx.sess.opts.optimize != OptLevel::No; pointee.safe = Some(PointerKind::Box { - unpin: optimize && boxed_ty.is_unpin(tcx, typing_env.param_env), + unpin: optimize && boxed_ty.is_unpin(tcx, typing_env), global: this.ty.is_box_global(tcx), }); } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 703a7826b7a..20c3f84bb4d 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1180,8 +1180,12 @@ impl<'tcx> Ty<'tcx> { /// does copies even when the type actually doesn't satisfy the /// full requirements for the `Copy` trait (cc #29149) -- this /// winds up being reported as an error during NLL borrow check. - pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self)) + pub fn is_copy_modulo_regions( + self, + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ) -> bool { + self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(typing_env.as_query_input(self)) } /// Checks whether values of this type `T` have a size known at @@ -1190,8 +1194,8 @@ impl<'tcx> Ty<'tcx> { /// over-approximation in generic contexts, where one can have /// strange rules like `>::Bar: Sized` that /// actually carry lifetime requirements. - pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self)) + pub fn is_sized(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + self.is_trivially_sized(tcx) || tcx.is_sized_raw(typing_env.as_query_input(self)) } /// Checks whether values of this type `T` implement the `Freeze` @@ -1201,8 +1205,8 @@ impl<'tcx> Ty<'tcx> { /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is /// effectively an implementation detail. - pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self)) + pub fn is_freeze(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + self.is_trivially_freeze() || tcx.is_freeze_raw(typing_env.as_query_input(self)) } /// Fast path helper for testing if a type is `Freeze`. @@ -1241,8 +1245,8 @@ impl<'tcx> Ty<'tcx> { } /// Checks whether values of this type `T` implement the `Unpin` trait. - pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self)) + pub fn is_unpin(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + self.is_trivially_unpin() || tcx.is_unpin_raw(typing_env.as_query_input(self)) } /// Fast path helper for testing if a type is `Unpin`. diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index aad7d54833b..159959d4f1f 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -165,11 +165,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if tcx.features().unsized_fn_params() { let ty = expr.ty; - let param_env = this.param_env; - - if !ty.is_sized(tcx, param_env) { + if !ty.is_sized(tcx, this.typing_env()) { // !sized means !copy, so this is an unsized move - assert!(!ty.is_copy_modulo_regions(tcx, param_env)); + assert!(!ty.is_copy_modulo_regions(tcx, this.typing_env())); // As described above, detect the case where we are passing a value of unsized // type, and that value is coming from the deref of a box. diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index cf8dc597b7b..3317f3b7f8a 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -148,6 +148,10 @@ struct BlockContext(Vec); struct Builder<'a, 'tcx> { tcx: TyCtxt<'tcx>, + // FIXME(@lcnr): Why does this use an `infcx`, there should be + // no shared type inference going on here. I feel like it would + // clearer to manually construct one where necessary or to provide + // a nice API for non-type inference trait system checks. infcx: InferCtxt<'tcx>, region_scope_tree: &'tcx region::ScopeTree, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index da6b52ce0b8..4a64a1f0f3e 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -11,7 +11,7 @@ use rustc_middle::span_bug; use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::Level; use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_span::def_id::{DefId, LocalDefId}; @@ -37,7 +37,7 @@ struct UnsafetyVisitor<'a, 'tcx> { /// of the LHS and the span of the assignment expression. assignment_info: Option>, in_union_destructure: bool, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, inside_adt: bool, warnings: &'a mut Vec, @@ -213,7 +213,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { body_target_features: self.body_target_features, assignment_info: self.assignment_info, in_union_destructure: false, - param_env: self.param_env, + typing_env: self.typing_env, inside_adt: false, warnings: self.warnings, suggest_unsafe_block: self.suggest_unsafe_block, @@ -370,7 +370,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { }; match rm { Mutability::Not => { - if !ty.is_freeze(self.tcx, self.param_env) { + if !ty.is_freeze(self.tcx, self.typing_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } } @@ -566,9 +566,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { && adt_def.is_union() { if let Some(assigned_ty) = self.assignment_info { - if assigned_ty - .needs_drop(self.tcx, ty::TypingEnv::from_param_env(self.param_env)) - { + if assigned_ty.needs_drop(self.tcx, self.typing_env) { // This would be unsafe, but should be outright impossible since we // reject such unions. assert!( @@ -608,7 +606,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if visitor.found { match borrow_kind { BorrowKind::Fake(_) | BorrowKind::Shared - if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) => + if !self.thir[arg].ty.is_freeze(self.tcx, self.typing_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } @@ -1026,7 +1024,8 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { body_target_features, assignment_info: None, in_union_destructure: false, - param_env: tcx.param_env(def), + // FIXME(#132279): we're clearly in a body here. + typing_env: ty::TypingEnv::non_body_analysis(tcx, def), inside_adt: false, warnings: &mut warnings, suggest_unsafe_block: true, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 73fcbeaef82..033501c66db 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -7,6 +7,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, struct_span_code_e use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, BindingMode, ByRef, HirId}; +use rustc_infer::traits::Reveal; use rustc_middle::bug; use rustc_middle::middle::limits::get_limit_size; use rustc_middle::thir::visit::Visitor; @@ -191,6 +192,15 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { } impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { + fn typing_env(&self) -> ty::TypingEnv<'tcx> { + // FIXME(#132279): We're in a body, should handle opaques. + debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing); + ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: self.param_env, + } + } + #[instrument(level = "trace", skip(self, f))] fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) { let old_let_source = self.let_source; @@ -760,7 +770,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: return; }; - let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()); let sess = cx.tcx.sess; diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6b462198db6..1b3243e097e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -203,8 +203,6 @@ impl<'tcx> ConstToPat<'tcx> { fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box> { let span = self.span; let tcx = self.tcx(); - let param_env = self.param_env; - let kind = match ty.kind() { ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { // Extremely important check for all ADTs! Make sure they opted-in to be used in @@ -276,7 +274,9 @@ impl<'tcx> ConstToPat<'tcx> { // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. _ => { - if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() { + if !pointee_ty.is_sized(tcx, self.infcx.typing_env(self.param_env)) + && !pointee_ty.is_slice() + { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; let e = tcx.dcx().emit_err(err); // We errored. Signal that in the pattern, so that follow up errors can be silenced. diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index a9600f77c0b..1b7c89fd251 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -3,7 +3,7 @@ use rustc_index::IndexVec; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Session; use tracing::{debug, trace}; @@ -25,9 +25,9 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { return; } + let typing_env = body.typing_env(tcx); let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &mut body.local_decls; - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); // This pass inserts new blocks. Each insertion changes the Location for all // statements/blocks after. Iterating or visiting the MIR in order would require updating @@ -41,7 +41,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { let source_info = statement.source_info; let mut finder = - PointerFinder { tcx, local_decls, param_env, pointers: Vec::new() }; + PointerFinder { tcx, local_decls, typing_env, pointers: Vec::new() }; finder.visit_statement(statement, location); for (local, ty) in finder.pointers { @@ -65,7 +65,7 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { struct PointerFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a mut LocalDecls<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, } @@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { let pointee_ty = pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. - if !pointee_ty.is_sized(self.tcx, self.param_env) { + if !pointee_ty.is_sized(self.tcx, self.typing_env) { debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty); return; } diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 7d6ae9843b1..9b3443d3209 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -28,8 +28,8 @@ impl<'tcx> crate::MirPass<'tcx> for CopyProp { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); let fully_moved = fully_moved_locals(&ssa, body); debug!(?fully_moved); diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index db72ec522a2..67b215c7c9d 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -208,7 +208,7 @@ pub(super) fn deduced_param_attrs<'tcx>( // blow-up in compile times: #113372 && tcx .normalize_erasing_regions(typing_env, local_decl.ty) - .is_freeze(tcx, typing_env.param_env), + .is_freeze(tcx, typing_env), }, ), ); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 27fe0ad72e7..5150cb752bd 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -120,12 +120,13 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); // Clone dominators because we need them while mutating the body. let dominators = body.basic_blocks.dominators().clone(); - let mut state = VnState::new(tcx, body, param_env, &ssa, dominators, &body.local_decls); + let mut state = + VnState::new(tcx, body, typing_env.param_env, &ssa, dominators, &body.local_decls); ssa.for_each_assignment_mut( body.basic_blocks.as_mut_preserves_cfg(), |local, value, location| { @@ -241,7 +242,6 @@ enum Value<'tcx> { struct VnState<'body, 'tcx> { tcx: TyCtxt<'tcx>, ecx: InterpCx<'tcx, DummyMachine>, - param_env: ty::ParamEnv<'tcx>, local_decls: &'body LocalDecls<'tcx>, /// Value stored in each local. locals: IndexVec>, @@ -281,7 +281,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { VnState { tcx, ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), - param_env, local_decls, locals: IndexVec::from_elem(None, local_decls), rev_locals: IndexVec::with_capacity(num_values), @@ -296,7 +295,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } fn typing_env(&self) -> ty::TypingEnv<'tcx> { - ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: self.param_env } + self.ecx.typing_env() } #[instrument(level = "trace", skip(self), ret)] @@ -347,7 +346,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Only register the value if its type is `Sized`, as we will emit copies of it. let is_sized = !self.feature_unsized_locals - || self.local_decls[local].ty.is_sized(self.tcx, self.param_env); + || self.local_decls[local].ty.is_sized(self.tcx, self.typing_env()); if is_sized { self.rev_locals[value].push(local); } @@ -642,7 +641,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ty = place.ty(self.local_decls, self.tcx).ty; if let Some(Mutability::Not) = ty.ref_mutability() && let Some(pointee_ty) = ty.builtin_deref(true) - && pointee_ty.is_freeze(self.tcx, self.param_env) + && pointee_ty.is_freeze(self.tcx, self.typing_env()) { // An immutable borrow `_x` always points to the same value for the // lifetime of the borrow, so we can merge all instances of `*_x`. @@ -1061,7 +1060,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() && from_mtbl == output_mtbl - && from_pointee_ty.is_sized(self.tcx, self.param_env) + && from_pointee_ty.is_sized(self.tcx, self.typing_env()) { fields[0] = *cast_value; *data_pointer_ty = *cast_from; @@ -1383,7 +1382,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = self.get(value) && let ty::RawPtr(to_pointee, _) = to.kind() - && to_pointee.is_sized(self.tcx, self.param_env) + && to_pointee.is_sized(self.tcx, self.typing_env()) { from = *data_pointer_ty; value = fields[0]; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index fcb51fbddd9..00f6c3845d4 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -199,10 +199,7 @@ impl<'tcx> Inliner<'tcx> { let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; for arg in args { - if !arg - .node - .ty(&caller_body.local_decls, self.tcx) - .is_sized(self.tcx, self.typing_env.param_env) + if !arg.node.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.typing_env) { // We do not allow inlining functions with unsized params. Inlining these functions // could create unsized locals, which are unsound and being phased out. diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 3911b0a2db6..67afd19aa73 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -451,7 +451,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if rvalue.has_param() { return None; } - if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.typing_env.param_env) { + if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.typing_env) { // the interpreter doesn't support unsized locals (only unsized arguments), // but rustc does (in a kinda broken way), so we have to skip them here return None; diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index b11b503e8d4..af438ac2177 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -85,8 +85,8 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { } fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - let ssa = SsaLocals::new(tcx, body, param_env); + let typing_env = body.typing_env(tcx); + let ssa = SsaLocals::new(tcx, body, typing_env); let mut replacer = compute_replacement(tcx, body, &ssa); debug!(?replacer.targets); diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 84df666e34a..5653aef0aae 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -13,7 +13,7 @@ use rustc_middle::bug; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::{ParamEnv, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use tracing::{debug, instrument, trace}; pub(super) struct SsaLocals { @@ -42,7 +42,7 @@ impl SsaLocals { pub(super) fn new<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> SsaLocals { let assignment_order = Vec::with_capacity(body.local_decls.len()); @@ -80,7 +80,7 @@ impl SsaLocals { // have already been marked as non-SSA. debug!(?visitor.borrowed_locals); for local in visitor.borrowed_locals.iter() { - if !body.local_decls[local].ty.is_freeze(tcx, param_env) { + if !body.local_decls[local].ty.is_freeze(tcx, typing_env) { visitor.assignments[local] = Set1::Many; } } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index ae0e6f594ee..724238ecfc9 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -623,7 +623,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if let Operand::Copy(place) = operand { let ty = place.ty(&self.body.local_decls, self.tcx).ty; - if !ty.is_copy_modulo_regions(self.tcx, self.typing_env.param_env) { + if !ty.is_copy_modulo_regions(self.tcx, self.typing_env) { self.fail(location, format!("`Operand::Copy` with non-`Copy` type {ty}")); } } @@ -989,7 +989,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } // FIXME: check `Thin` instead of `Sized` - if !in_pointee.is_sized(self.tcx, self.typing_env.param_env) { + if !in_pointee.is_sized(self.tcx, self.typing_env) { self.fail(location, "input pointer must be thin"); } } else { @@ -1004,7 +1004,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self.mir_assign_valid_types(metadata_ty, self.tcx.types.usize) { self.fail(location, "slice metadata must be usize"); } - } else if pointee_ty.is_sized(self.tcx, self.typing_env.param_env) { + } else if pointee_ty.is_sized(self.tcx, self.typing_env) { if metadata_ty != self.tcx.types.unit { self.fail(location, "metadata for pointer-to-thin must be unit"); } @@ -1294,7 +1294,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self .tcx .normalize_erasing_regions(self.typing_env, op_ty) - .is_sized(self.tcx, self.typing_env.param_env) + .is_sized(self.tcx, self.typing_env) { self.fail( location, @@ -1304,7 +1304,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self .tcx .normalize_erasing_regions(self.typing_env, *target_type) - .is_sized(self.tcx, self.typing_env.param_env) + .is_sized(self.tcx, self.typing_env) { self.fail( location, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1b94c627f81..8ee9ac3df72 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1036,7 +1036,7 @@ fn find_vtable_types_for_unsizing<'tcx>( let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let typing_env = ty::TypingEnv::fully_monomorphized(); let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.tcx, typing_env.param_env) { + if ty.is_sized(tcx.tcx, typing_env) { return false; } let tail = tcx.struct_tail_for_codegen(ty, typing_env); diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 8f1c8a29663..43244eb5dcb 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -32,8 +32,10 @@ impl<'tcx> InferCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); + // FIXME(#132279): This should be removed as it causes us to incorrectly + // handle opaques in their defining scope. if !(param_env, ty).has_infer() { - return ty.is_copy_modulo_regions(self.tcx, param_env); + return ty.is_copy_modulo_regions(self.tcx, self.typing_env(param_env)); } let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index e2283383196..a5a9125c8b5 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -397,7 +397,7 @@ fn adjust_for_rust_scalar<'tcx>( Some(kind) } else if let Some(pointee) = drop_target_pointee { // The argument to `drop_in_place` is semantically equivalent to a mutable reference. - Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.typing_env.param_env) }) + Some(PointerKind::MutableRef { unpin: pointee.is_unpin(tcx, cx.typing_env) }) } else { None }; diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index c26b41d8960..2157ab3c402 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -3,34 +3,33 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_trait_selection::traits; -fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Copy) } -fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Sized) } -fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Freeze) } -fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { +fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Unpin) } fn is_item_raw<'tcx>( tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, item: LangItem, ) -> bool { - let (param_env, ty) = query.into_parts(); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(query.typing_env); let trait_def_id = tcx.require_lang_item(item, None); - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); - traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) + traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, query.value, trait_def_id) } pub(crate) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 02ee3f32915..092e140a600 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -105,7 +105,7 @@ fn map_error<'tcx>( // This is sometimes not a compile error if there are trivially false where clauses. // See `tests/ui/layout/trivial-bounds-sized.rs` for an example. assert!(field.layout.is_unsized(), "invalid layout error {err:#?}"); - if !field.ty.is_sized(cx.tcx(), cx.typing_env.param_env) { + if !field.ty.is_sized(cx.tcx(), cx.typing_env) { cx.tcx().dcx().delayed_bug(format!( "encountered unexpected unsized field in layout of {ty:?}: {field:#?}" )); @@ -236,7 +236,7 @@ fn layout_of_uncached<'tcx>( } let pointee = tcx.normalize_erasing_regions(cx.typing_env, pointee); - if pointee.is_sized(tcx, cx.typing_env.param_env) { + if pointee.is_sized(tcx, cx.typing_env) { return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } @@ -594,8 +594,8 @@ fn layout_of_uncached<'tcx>( let maybe_unsized = def.is_struct() && def.non_enum_variant().tail_opt().is_some_and(|last_field| { - let param_env = tcx.param_env(def.did()); - !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, param_env) + let typing_env = ty::TypingEnv::post_analysis(tcx, def.did()); + !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, typing_env) }); let layout = cx @@ -620,11 +620,7 @@ fn layout_of_uncached<'tcx>( // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around. if cfg!(debug_assertions) && maybe_unsized - && def - .non_enum_variant() - .tail() - .ty(tcx, args) - .is_sized(tcx, cx.typing_env.param_env) + && def.non_enum_variant().tail().ty(tcx, args).is_sized(tcx, cx.typing_env) { let mut variants = variants; let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap(); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index d462dbd9416..03ab3a55486 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -186,7 +186,7 @@ where } } - _ if component.is_copy_modulo_regions(tcx, self.typing_env.param_env) => (), + _ if component.is_copy_modulo_regions(tcx, self.typing_env) => (), ty::Closure(_, args) => { for upvar in args.as_closure().upvar_tys() { diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 31e4e79c00a..685fd922d91 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -42,7 +42,7 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>( }) .collect(); // We are only interested in case the type *doesn't* implement the `Sized` trait. - if !ty.is_sized(tcx, param_env) + if !ty.is_sized(tcx, ty::TypingEnv::from_param_env(param_env)) && let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() && let Some(impl_item) = synthesize_auto_trait_impl( cx, diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index 86c5f6b9f0b..46d67e615c7 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -39,7 +39,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut)) // The `U` in `pointer::cast` have to be `Sized` // as explained here: https://github.com/rust-lang/rust/issues/60602. - && to_pointee_ty.is_sized(cx.tcx, cx.param_env) + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) { let mut app = Applicability::MachineApplicable; let turbofish = match &cast_to_hir_ty.kind { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index f864b7a5a8a..9049739dddb 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1028,7 +1028,7 @@ fn report<'tcx>( State::ExplicitDeref { mutability } => { if is_block_like(expr) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind() - && ty.is_sized(cx.tcx, cx.param_env) + && ty.is_sized(cx.tcx, cx.typing_env()) { // Rustc bug: auto deref doesn't work on block expression when targeting sized types. return; diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index c74ba088b78..175d92d2d79 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -198,7 +198,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(adt, args) => { - tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env) + tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.typing_env()) || matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc)) && args.types().any(|ty| is_mutable_ty(cx, ty, tys)) }, diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 0e488cee6b7..5db28e9ae9b 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { let has_interior_mutability = !cx .typeck_results() .node_type(canonical_id) - .is_freeze(cx.tcx, cx.param_env); + .is_freeze(cx.tcx, cx.typing_env()); if has_interior_mutability { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index 223b0630bfd..7aa13d8d5b6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -148,7 +148,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: _ => {}, } } - requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + requires_copy |= !ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()); break; } }, @@ -158,9 +158,9 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: } if can_lint - && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env)) + && (!requires_copy || arg_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env())) // This case could be handled, but a fair bit of care would need to be taken. - && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.param_env)) + && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env())) { if requires_deref { edits.push((param.span.shrink_to_lo(), "&".into())); diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 6cddd7ea813..e2ab5e98504 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -80,7 +80,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> { "generally you want to avoid `&mut &mut _` if possible", ); } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() { - if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) { + if ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env()) { span_lint_hir( self.cx, MUT_MUT, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 0775d7abdbb..ad0ab148530 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -180,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if !is_self(arg) && !ty.is_mutable_ptr() && !is_copy(cx, ty) - && ty.is_sized(cx.tcx, cx.param_env) + && ty.is_sized(cx.tcx, cx.typing_env()) && !allowed_traits.iter().any(|&t| { implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< ty::GenericArg<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index a00fd01a62e..f69cb9be4ca 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -251,7 +251,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); - let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) && !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); let sugg = if let Some(else_inner) = r#else { if eq_expr_value(cx, caller, peel_blocks(else_inner)) { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 0772b284968..bf6700b1b6b 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { if from_mutbl == to_mutbl - && to_pointee_ty.is_sized(cx.tcx, cx.param_env) + && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) && msrv.meets(msrvs::POINTER_CAST) { diag.span_suggestion_verbose( diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 4dc1290e8b1..48d65eb15d9 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -206,12 +206,12 @@ fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: T continue; }, (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)), _) - if !unsized_ty.is_sized(cx.tcx, cx.param_env) => + if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) => { (true, false) }, (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _))) - if !unsized_ty.is_sized(cx.tcx, cx.param_env) => + if !unsized_ty.is_sized(cx.tcx, cx.typing_env()) => { (false, true) }, diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs index 1a656088b17..de3456a8ba5 100644 --- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs +++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath: // here because `mod.rs` guarantees this lint is only run on types outside of bodies and // is not run on locals. let ty = lower_ty(cx.tcx, hir_ty); - if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.param_env) { + if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.typing_env()) { return false; } hir_ty.span diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index 230239335c6..9b236d3bda5 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( && let boxed_alloc_ty = last.args.get(1) && let ty_ty = lower_ty(cx.tcx, boxed_ty) && !ty_ty.has_escaping_bound_vars() - && ty_ty.is_sized(cx.tcx, cx.param_env) + && ty_ty.is_sized(cx.tcx, cx.typing_env()) && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) && ty_ty_size < box_size_threshold // https://github.com/rust-lang/rust-clippy/issues/7114 diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index 14f4aa6676b..34df1d5560a 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -82,7 +82,7 @@ impl UnnecessaryBoxReturns { // It's sometimes useful to return Box if T is unsized, so don't lint those. // Also, don't lint if we know that T is very large, in which case returning // a Box may be beneficial. - if boxed_ty.is_sized(cx.tcx, cx.param_env) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { + if boxed_ty.is_sized(cx.tcx, cx.typing_env()) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { span_lint_and_then( cx, UNNECESSARY_BOX_RETURNS, diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 2aad867dc0d..fff516b730d 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -38,7 +38,7 @@ pub use type_certainty::expr_type_is_certain; /// Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - ty.is_copy_modulo_regions(cx.tcx, cx.param_env) + ty.is_copy_modulo_regions(cx.tcx, cx.typing_env()) } /// This checks whether a given type is known to implement Debug. diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 745316913d9..f46557ac630 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -12,7 +12,6 @@ use std::{cmp, mem}; use rustc_abi::{BackendRepr, Size}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Mutability, RetagKind}; -use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty}; use self::diagnostics::{RetagCause, RetagInfo}; @@ -71,7 +70,7 @@ impl NewPermission { access: None, protector: None, } - } else if pointee.is_unpin(*cx.tcx, cx.param_env()) { + } else if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`. NewPermission::Uniform { perm: Permission::Unique, @@ -129,7 +128,7 @@ impl NewPermission { fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). let pointee = ty.builtin_deref(true).unwrap(); - if pointee.is_unpin(*cx.tcx, cx.param_env()) { + if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). NewPermission::Uniform { @@ -608,7 +607,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { match new_perm { NewPermission::Uniform { perm, .. } => write!(kind_str, "{perm:?} permission").unwrap(), - NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.param_env()) => + NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env()) => write!(kind_str, "{freeze_perm:?} permission").unwrap(), NewPermission::FreezeSensitive { freeze_perm, nonfreeze_perm, .. } => write!(kind_str, "{freeze_perm:?}/{nonfreeze_perm:?} permission for frozen/non-frozen parts").unwrap(), diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 255a3578aae..8f8e29846c9 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -1,6 +1,5 @@ use rustc_abi::{BackendRepr, Size}; use rustc_middle::mir::{Mutability, RetagKind}; -use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefId; @@ -132,8 +131,8 @@ impl<'tcx> NewPermission { kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>, ) -> Option { - let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.param_env()); - let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.param_env()); + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); + let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env()); let is_protected = kind == RetagKind::FnEntry; // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`, // interior mutability and protectors interact poorly. @@ -164,10 +163,10 @@ impl<'tcx> NewPermission { zero_size: bool, ) -> Option { let pointee = ty.builtin_deref(true).unwrap(); - pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| { + pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. - let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.param_env()); + let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env()); let protected = kind == RetagKind::FnEntry; let initial_state = Permission::new_reserved(ty_is_freeze, protected); Self { @@ -521,7 +520,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Note: if we were to inline `new_reserved` below we would find out that // `ty_is_freeze` is eventually unused because it appears in a `ty_is_freeze || true`. // We are nevertheless including it here for clarity. - let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.param_env()); + let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); // Retag it. With protection! That is the entire point. let new_perm = NewPermission { initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true), -- cgit 1.4.1-3-g733a5 From 1ec964873e3e8552de95d853214abee34d4c6689 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 16:51:47 +0100 Subject: unconditional recursion, yeet `TypingEnv::from_param_env` --- compiler/rustc_mir_build/src/lints.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index a1b75c22c4d..5cf33868ade 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -132,21 +132,16 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> { return false; } let caller = body.source.def_id(); - let param_env = tcx.param_env(caller); + let typing_env = body.typing_env(tcx); let func_ty = func.ty(body, tcx); if let ty::FnDef(callee, args) = *func_ty.kind() { - let Ok(normalized_args) = - tcx.try_normalize_erasing_regions(ty::TypingEnv::from_param_env(param_env), args) - else { + let Ok(normalized_args) = tcx.try_normalize_erasing_regions(typing_env, args) else { return false; }; - let (callee, call_args) = if let Ok(Some(instance)) = Instance::try_resolve( - tcx, - ty::TypingEnv::from_param_env(param_env), - callee, - normalized_args, - ) { + let (callee, call_args) = if let Ok(Some(instance)) = + Instance::try_resolve(tcx, typing_env, callee, normalized_args) + { (instance.def_id(), instance.args) } else { (callee, normalized_args) -- cgit 1.4.1-3-g733a5 From decf37bd16318dbd6545d23e1fd898d6cbd4f711 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 16:54:04 +0100 Subject: liveness checking, yeet `TypingEnv::from_param_env` --- compiler/rustc_passes/src/liveness.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index c6c99852952..9cd95a0b02d 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -468,7 +468,7 @@ const ACC_USE: u32 = 4; struct Liveness<'a, 'tcx> { ir: &'a mut IrMaps<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, closure_min_captures: Option<&'tcx RootVariableMinCaptureList<'tcx>>, successors: IndexVec>, rwu_table: rwu_table::RWUTable, @@ -491,7 +491,8 @@ struct Liveness<'a, 'tcx> { impl<'a, 'tcx> Liveness<'a, 'tcx> { fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> { let typeck_results = ir.tcx.typeck(body_owner); - let param_env = ir.tcx.param_env(body_owner); + // FIXME(#132279): we're in a body here. + let typing_env = ty::TypingEnv::non_body_analysis(ir.tcx, body_owner); let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner); let closure_ln = ir.add_live_node(ClosureNode); let exit_ln = ir.add_live_node(ExitNode); @@ -502,7 +503,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { Liveness { ir, typeck_results, - param_env, + typing_env, closure_min_captures, successors: IndexVec::from_elem_n(None, num_live_nodes), rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars), @@ -1297,7 +1298,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { let ty = self.typeck_results.expr_ty(expr); let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id(); - if ty.is_inhabited_from(self.ir.tcx, m, ty::TypingEnv::from_param_env(self.param_env)) { + if ty.is_inhabited_from(self.ir.tcx, m, self.typing_env) { return succ; } match self.ir.lnks[succ] { -- cgit 1.4.1-3-g733a5 From 07a527247661ef8ef31dacf9c28928c62f8bb586 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 17:05:23 +0100 Subject: pattern lowering, yeet `TypingEnv::from_param_env` --- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 91 ++++++++-------------- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 8 +- 3 files changed, 38 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index dfc180f5261..d47f7154c4b 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -123,7 +123,7 @@ impl<'tcx> Cx<'tcx> { #[instrument(level = "debug", skip(self))] fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box> { - pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p) + pat_from_hir(self.tcx, self.typing_env(), self.typeck_results(), p) } fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 1b3243e097e..a40134e44e7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -2,11 +2,11 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_apfloat::Float; use rustc_hir as hir; use rustc_index::Idx; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; use rustc_middle::{mir, span_bug}; use rustc_span::Span; use rustc_trait_selection::traits::ObligationCause; @@ -35,10 +35,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { id: hir::HirId, span: Span, ) -> Box> { - // FIXME(#132279): We likely want to be able to reveal the hidden types - // of opaques defined in this function here. - let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); - let mut convert = ConstToPat::new(self, id, span, infcx); + let mut convert = ConstToPat::new(self, id, span); match c.kind() { ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty), @@ -49,27 +46,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } struct ConstToPat<'tcx> { + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, span: Span, - // inference context used for checking `T: Structural` bounds. - infcx: InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - treat_byte_string_as_slice: bool, } impl<'tcx> ConstToPat<'tcx> { - fn new( - pat_ctxt: &PatCtxt<'_, 'tcx>, - id: hir::HirId, - span: Span, - infcx: InferCtxt<'tcx>, - ) -> Self { + fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span) -> Self { trace!(?pat_ctxt.typeck_results.hir_owner); ConstToPat { + tcx: pat_ctxt.tcx, + typing_env: pat_ctxt.typing_env, span, - infcx, - param_env: pat_ctxt.param_env, treat_byte_string_as_slice: pat_ctxt .typeck_results .treat_byte_string_as_slice @@ -77,16 +67,8 @@ impl<'tcx> ConstToPat<'tcx> { } } - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn typing_env(&self) -> ty::TypingEnv<'tcx> { - self.infcx.typing_env(self.param_env) - } - fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { - ty.is_structural_eq_shallow(self.infcx.tcx) + ty.is_structural_eq_shallow(self.tcx) } fn unevaluated_to_pat( @@ -105,22 +87,21 @@ impl<'tcx> ConstToPat<'tcx> { // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All` // instead of having this logic here let typing_env = - self.tcx().erase_regions(self.typing_env()).with_reveal_all_normalized(self.tcx()); - let uv = self.tcx().erase_regions(uv); + self.tcx.erase_regions(self.typing_env).with_reveal_all_normalized(self.tcx); + let uv = self.tcx.erase_regions(uv); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) - { + let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) { Ok(Ok(c)) => c, Err(ErrorHandled::Reported(_, _)) => { // Let's tell the use where this failing const occurs. - let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span }); + let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span: self.span }); return pat_from_kind(PatKind::Error(e)); } Err(ErrorHandled::TooGeneric(_)) => { let e = self - .tcx() + .tcx .dcx() .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }); return pat_from_kind(PatKind::Error(e)); @@ -130,13 +111,13 @@ impl<'tcx> ConstToPat<'tcx> { let e = match bad_ty.kind() { ty::Adt(def, ..) => { assert!(def.is_union()); - self.tcx().dcx().emit_err(UnionPattern { span: self.span }) + self.tcx.dcx().emit_err(UnionPattern { span: self.span }) } ty::FnPtr(..) | ty::RawPtr(..) => { - self.tcx().dcx().emit_err(PointerPattern { span: self.span }) + self.tcx.dcx().emit_err(PointerPattern { span: self.span }) } _ => self - .tcx() + .tcx .dcx() .emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }), }; @@ -151,7 +132,7 @@ impl<'tcx> ConstToPat<'tcx> { // Always check for `PartialEq` if we had no other errors yet. if !self.type_has_partial_eq_impl(ty) { let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty }; - let e = self.tcx().dcx().emit_err(err); + let e = self.tcx.dcx().emit_err(err); return pat_from_kind(PatKind::Error(e)); } } @@ -161,18 +142,19 @@ impl<'tcx> ConstToPat<'tcx> { #[instrument(level = "trace", skip(self), ret)] fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { - let tcx = self.tcx(); + let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); // double-check there even *is* a semantic `PartialEq` to dispatch to. // // (If there isn't, then we can safely issue a hard // error, because that's never worked, due to compiler // using `PartialEq::eq` in this scenario in the past.) - let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let partial_eq_trait_id = + self.tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span)); let partial_eq_obligation = Obligation::new( - tcx, + self.tcx, ObligationCause::dummy(), - self.param_env, - ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]), + param_env, + ty::TraitRef::new(self.tcx, partial_eq_trait_id, [ty, ty]), ); // This *could* accept a type that isn't actually `PartialEq`, because region bounds get @@ -181,7 +163,7 @@ impl<'tcx> ConstToPat<'tcx> { // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck // can ensure that the type really implements `PartialEq`. - self.infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation) + infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation) } fn field_pats( @@ -192,7 +174,7 @@ impl<'tcx> ConstToPat<'tcx> { .map(|(idx, (val, ty))| { let field = FieldIdx::new(idx); // Patterns can only use monomorphic types. - let ty = self.tcx().normalize_erasing_regions(self.typing_env(), ty); + let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty); FieldPat { field, pattern: self.valtree_to_pat(val, ty) } }) .collect() @@ -202,12 +184,12 @@ impl<'tcx> ConstToPat<'tcx> { #[instrument(skip(self), level = "debug")] fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box> { let span = self.span; - let tcx = self.tcx(); + let tcx = self.tcx; let kind = match ty.kind() { ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { // Extremely important check for all ADTs! Make sure they opted-in to be used in // patterns. - debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,); + debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty); let err = TypeNotStructural { span, non_sm_ty: ty }; let e = tcx.dcx().emit_err(err); // We errored. Signal that in the pattern, so that follow up errors can be silenced. @@ -225,7 +207,7 @@ impl<'tcx> ConstToPat<'tcx> { adt_def.variants()[variant_index] .fields .iter() - .map(|field| field.ty(self.tcx(), args)), + .map(|field| field.ty(self.tcx, args)), ), ), } @@ -233,14 +215,9 @@ impl<'tcx> ConstToPat<'tcx> { ty::Adt(def, args) => { assert!(!def.is_union()); // Valtree construction would never succeed for unions. PatKind::Leaf { - subpatterns: self.field_pats( - cv.unwrap_branch().iter().copied().zip( - def.non_enum_variant() - .fields - .iter() - .map(|field| field.ty(self.tcx(), args)), - ), - ), + subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip( + def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx, args)), + )), } } ty::Tuple(fields) => PatKind::Leaf { @@ -274,9 +251,7 @@ impl<'tcx> ConstToPat<'tcx> { // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. _ => { - if !pointee_ty.is_sized(tcx, self.infcx.typing_env(self.param_env)) - && !pointee_ty.is_slice() - { + if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; let e = tcx.dcx().emit_err(err); // We errored. Signal that in the pattern, so that follow up errors can be silenced. diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d17bc8566cc..6b9e3b85999 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -30,7 +30,7 @@ use crate::thir::util::UserAnnotatedTyHelpers; struct PatCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, /// Used by the Rust 2024 migration lint. @@ -39,13 +39,13 @@ struct PatCtxt<'a, 'tcx> { pub(super) fn pat_from_hir<'a, 'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, ) -> Box> { let mut pcx = PatCtxt { tcx, - param_env, + typing_env, typeck_results, rust_2024_migration_suggestion: typeck_results .rust_2024_migration_desugared_pats() @@ -242,7 +242,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity); let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity); - let cmp = lo.compare_with(hi, ty, self.tcx, ty::TypingEnv::from_param_env(self.param_env)); + let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env); let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty })); match (end, cmp) { // `x..y` where `x < y`. -- cgit 1.4.1-3-g733a5 From ffd7a50314c81a0137d5b2b04b5c31dfb017f7ea Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 17:07:19 +0100 Subject: impl trait overcaptures, yeet ` TypingMode::from_param_env` --- compiler/rustc_lint/src/impl_trait_overcaptures.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index beab4d4e6a9..1aacdbd448c 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; @@ -186,8 +186,8 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { functional_variances.variances }), outlives_env: LazyCell::new(|| { - let param_env = tcx.param_env(parent_def_id); - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, parent_def_id); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let ocx = ObligationCtxt::new(&infcx); let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default(); let implied_bounds = -- cgit 1.4.1-3-g733a5 From f74951fdf1a46af01efdc72f50f1df2a7cb49b49 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 17:17:00 +0100 Subject: generic_const_exprs: yeet `TypingEnv::from_param_env` --- compiler/rustc_hir_typeck/src/writeback.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 8694800ac43..2f436ce77a4 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -831,8 +831,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { // Normalize consts in writeback, because GCE doesn't normalize eagerly. if tcx.features().generic_const_exprs() { - value = - value.fold_with(&mut EagerlyNormalizeConsts { tcx, param_env: self.fcx.param_env }); + value = value.fold_with(&mut EagerlyNormalizeConsts::new(self.fcx)); } value @@ -873,16 +872,22 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { struct EagerlyNormalizeConsts<'tcx> { tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, } +impl<'tcx> EagerlyNormalizeConsts<'tcx> { + fn new(fcx: &FnCtxt<'_, 'tcx>) -> Self { + // FIXME(#132279, generic_const_exprs): Using `try_normalize_erasing_regions` here + // means we can't handle opaque types in their defining scope. + EagerlyNormalizeConsts { tcx: fcx.tcx, typing_env: fcx.typing_env(fcx.param_env) } + } +} + impl<'tcx> TypeFolder> for EagerlyNormalizeConsts<'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.tcx } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - self.tcx - .try_normalize_erasing_regions(ty::TypingEnv::from_param_env(self.param_env), ct) - .unwrap_or(ct) + self.tcx.try_normalize_erasing_regions(self.typing_env, ct).unwrap_or(ct) } } -- cgit 1.4.1-3-g733a5 From 4813fda2e6d89c948c56685e83c1dcb90ed30f5d Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 18:07:55 +0100 Subject: rustdoc: yeet `TypingEnv::from_param_env` --- compiler/rustc_trait_selection/src/traits/auto_trait.rs | 13 ++++--------- src/librustdoc/clean/auto_trait.rs | 12 ++++++------ src/librustdoc/clean/mod.rs | 4 +--- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 103f7c76a86..fac0414d714 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -9,7 +9,6 @@ use rustc_data_structures::unord::UnordSet; use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::ty::{Region, RegionVid}; use tracing::debug; -use ty::TypingMode; use super::*; use crate::errors::UnableToConstructConstantValue; @@ -71,7 +70,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { pub fn find_auto_trait_generics( &self, ty: Ty<'tcx>, - orig_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, trait_did: DefId, mut auto_trait_callback: impl FnMut(AutoTraitInfo<'tcx>) -> A, ) -> AutoTraitResult { @@ -79,7 +78,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]); - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let (infcx, orig_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let mut selcx = SelectionContext::new(&infcx); for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] { let result = selcx.select(&Obligation::new( @@ -89,17 +88,13 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::TraitPredicate { trait_ref, polarity }, )); if let Ok(Some(ImplSource::UserDefined(_))) = result { - debug!( - "find_auto_trait_generics({:?}): \ - manual impl found, bailing out", - trait_ref - ); + debug!("find_auto_trait_generics({trait_ref:?}): manual impl found, bailing out"); // If an explicit impl exists, it always takes priority over an auto impl return AutoTraitResult::ExplicitImpl; } } - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let (infcx, orig_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let mut fresh_preds = FxIndexSet::default(); // Due to the way projections are handled by SelectionContext, we need to run diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 685fd922d91..3fe567b1c39 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -21,7 +21,7 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>( item_def_id: DefId, ) -> Vec { let tcx = cx.tcx; - let param_env = tcx.param_env(item_def_id); + let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); let ty = tcx.type_of(item_def_id).instantiate_identity(); let finder = auto_trait::AutoTraitFinder::new(tcx); @@ -34,7 +34,7 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>( cx, ty, trait_def_id, - param_env, + typing_env, item_def_id, &finder, DiscardPositiveImpls::No, @@ -42,13 +42,13 @@ pub(crate) fn synthesize_auto_trait_impls<'tcx>( }) .collect(); // We are only interested in case the type *doesn't* implement the `Sized` trait. - if !ty.is_sized(tcx, ty::TypingEnv::from_param_env(param_env)) + if !ty.is_sized(tcx, typing_env) && let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() && let Some(impl_item) = synthesize_auto_trait_impl( cx, ty, sized_trait_def_id, - param_env, + typing_env, item_def_id, &finder, DiscardPositiveImpls::Yes, @@ -64,7 +64,7 @@ fn synthesize_auto_trait_impl<'tcx>( cx: &mut DocContext<'tcx>, ty: Ty<'tcx>, trait_def_id: DefId, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, item_def_id: DefId, finder: &auto_trait::AutoTraitFinder<'tcx>, discard_positive_impls: DiscardPositiveImpls, @@ -76,7 +76,7 @@ fn synthesize_auto_trait_impl<'tcx>( return None; } - let result = finder.find_auto_trait_generics(ty, param_env, trait_def_id, |info| { + let result = finder.find_auto_trait_generics(ty, typing_env, trait_def_id, |info| { clean_param_env(cx, item_def_id, info.full_user_env, info.region_data, info.vid_to_region) }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f0787d286fd..4b2b8de4cd8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1817,9 +1817,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) = const_arg.kind { - // Only anon consts can implicitly capture params. - // FIXME: is this correct behavior? - let typing_env = ty::TypingEnv::from_param_env(cx.tcx.param_env(*def_id)); + let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id); cx.tcx.normalize_erasing_regions(typing_env, ct) } else { ct -- cgit 1.4.1-3-g733a5 From 7ac4c04731ecb6eedd63a1f899a0c6207679cbf9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 22 May 2024 14:10:52 +0200 Subject: Add std::thread::add_spawn_hook. --- library/std/src/thread/mod.rs | 11 +++++ library/std/src/thread/spawnhook.rs | 92 +++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 library/std/src/thread/spawnhook.rs diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 227ee9d64f3..ee8d688398d 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -188,6 +188,11 @@ mod current; pub use current::current; pub(crate) use current::{current_id, drop_current, set_current, try_current}; +mod spawnhook; + +#[unstable(feature = "thread_spawn_hook", issue = "none")] +pub use spawnhook::add_spawn_hook; + //////////////////////////////////////////////////////////////////////////////// // Thread-local storage //////////////////////////////////////////////////////////////////////////////// @@ -485,6 +490,9 @@ impl Builder { Some(name) => Thread::new(id, name.into()), None => Thread::new_unnamed(id), }; + + let hooks = spawnhook::run_spawn_hooks(&my_thread)?; + let their_thread = my_thread.clone(); let my_packet: Arc> = Arc::new(Packet { @@ -535,6 +543,9 @@ impl Builder { } crate::io::set_output_capture(output_capture); + for hook in hooks { + hook(); + } let f = f.into_inner(); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs new file mode 100644 index 00000000000..c64aea4262b --- /dev/null +++ b/library/std/src/thread/spawnhook.rs @@ -0,0 +1,92 @@ +use crate::io; +use crate::sync::RwLock; +use crate::thread::Thread; + +static SPAWN_HOOKS: RwLock< + Vec<&'static (dyn Fn(&Thread) -> io::Result> + Sync)>, +> = RwLock::new(Vec::new()); + +/// Registers a function to run for every new thread spawned. +/// +/// The hook is executed in the parent thread, and returns a function +/// that will be executed in the new thread. +/// +/// The hook is called with the `Thread` handle for the new thread. +/// +/// If the hook returns an `Err`, thread spawning is aborted. In that case, the +/// function used to spawn the thread (e.g. `std::thread::spawn`) will return +/// the error returned by the hook. +/// +/// Hooks can only be added, not removed. +/// +/// The hooks will run in order, starting with the most recently added. +/// +/// # Usage +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// std::thread::add_spawn_hook(|_| { +/// ..; // This will run in the parent (spawning) thread. +/// Ok(move || { +/// ..; // This will run it the child (spawned) thread. +/// }) +/// }); +/// ``` +/// +/// # Example +/// +/// A spawn hook can be used to initialize thread locals from the parent thread: +/// +/// ``` +/// #![feature(thread_spawn_hook)] +/// +/// use std::cell::Cell; +/// +/// thread_local! { +/// static X: Cell = Cell::new(0); +/// } +/// +/// std::thread::add_spawn_hook(|_| { +/// // Get the value of X in the spawning thread. +/// let value = X.get(); +/// // Set the value of X in the newly spawned thread. +/// Ok(move || { +/// X.set(value); +/// }) +/// }); +/// +/// X.set(123); +/// +/// std::thread::spawn(|| { +/// assert_eq!(X.get(), 123); +/// }).join().unwrap(); +/// ``` +#[unstable(feature = "thread_spawn_hook", issue = "none")] +pub fn add_spawn_hook(hook: F) +where + F: 'static + Sync + Fn(&Thread) -> io::Result, + G: 'static + Send + FnOnce(), +{ + SPAWN_HOOKS.write().unwrap_or_else(|e| e.into_inner()).push(Box::leak(Box::new( + move |thread: &Thread| -> io::Result<_> { + let f: Box = Box::new(hook(thread)?); + Ok(f) + }, + ))); +} + +/// Runs all the spawn hooks. +/// +/// Called on the parent thread. +/// +/// Returns the functions to be called on the newly spawned thread. +pub(super) fn run_spawn_hooks(thread: &Thread) -> io::Result>> { + SPAWN_HOOKS + .read() + .unwrap_or_else(|e| e.into_inner()) + .iter() + .rev() + .map(|hook| hook(thread)) + .collect() +} -- cgit 1.4.1-3-g733a5 From ef9055f3eef409e99e1e786f6a90a1684fde810d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 22 May 2024 14:16:33 +0200 Subject: Use add_spawn_hook for libtest's output capturing. --- library/std/src/thread/mod.rs | 4 ---- library/test/src/lib.rs | 11 +++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index ee8d688398d..c6b1e0de84c 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -502,9 +502,6 @@ impl Builder { }); let their_packet = my_packet.clone(); - let output_capture = crate::io::set_output_capture(None); - crate::io::set_output_capture(output_capture.clone()); - // Pass `f` in `MaybeUninit` because actually that closure might *run longer than the lifetime of `F`*. // See for more details. // To prevent leaks we use a wrapper that drops its contents. @@ -542,7 +539,6 @@ impl Builder { imp::Thread::set_name(name); } - crate::io::set_output_capture(output_capture); for hook in hooks { hook(); } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 30ccfe2af8d..00a0b55c6a9 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -24,6 +24,7 @@ #![feature(process_exitcode_internals)] #![feature(panic_can_unwind)] #![feature(test)] +#![feature(thread_spawn_hook)] #![allow(internal_features)] #![warn(rustdoc::unescaped_backticks)] @@ -134,6 +135,16 @@ pub fn test_main(args: &[String], tests: Vec, options: Option Date: Thu, 24 Oct 2024 10:52:47 +0200 Subject: Update thread spawn hooks. 1. Make the effect thread local. 2. Don't return a io::Result from hooks. --- library/std/src/thread/mod.rs | 7 +-- library/std/src/thread/spawnhook.rs | 112 ++++++++++++++++++++++++++---------- library/test/src/lib.rs | 4 +- 3 files changed, 86 insertions(+), 37 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index c6b1e0de84c..79621e7fa6b 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -491,7 +491,7 @@ impl Builder { None => Thread::new_unnamed(id), }; - let hooks = spawnhook::run_spawn_hooks(&my_thread)?; + let hooks = spawnhook::run_spawn_hooks(&my_thread); let their_thread = my_thread.clone(); @@ -539,12 +539,9 @@ impl Builder { imp::Thread::set_name(name); } - for hook in hooks { - hook(); - } - let f = f.into_inner(); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { + crate::sys::backtrace::__rust_begin_short_backtrace(|| hooks.run()); crate::sys::backtrace::__rust_begin_short_backtrace(f) })); // SAFETY: `their_packet` as been built just above and moved by the diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index c64aea4262b..9c4e9eb6aa1 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -1,21 +1,43 @@ -use crate::io; -use crate::sync::RwLock; +use crate::cell::Cell; +use crate::sync::Arc; use crate::thread::Thread; -static SPAWN_HOOKS: RwLock< - Vec<&'static (dyn Fn(&Thread) -> io::Result> + Sync)>, -> = RwLock::new(Vec::new()); +// A thread local linked list of spawn hooks. +crate::thread_local! { + static SPAWN_HOOKS: Cell = const { Cell::new(SpawnHooks { first: None }) }; +} + +#[derive(Default, Clone)] +struct SpawnHooks { + first: Option>, +} + +// Manually implement drop to prevent deep recursion when dropping linked Arc list. +impl Drop for SpawnHooks { + fn drop(&mut self) { + let mut next = self.first.take(); + while let Some(SpawnHook { hook, next: n }) = next.and_then(|n| Arc::into_inner(n)) { + drop(hook); + next = n; + } + } +} + +struct SpawnHook { + hook: Box Box>, + next: Option>, +} -/// Registers a function to run for every new thread spawned. +/// Registers a function to run for every newly thread spawned. /// /// The hook is executed in the parent thread, and returns a function /// that will be executed in the new thread. /// /// The hook is called with the `Thread` handle for the new thread. /// -/// If the hook returns an `Err`, thread spawning is aborted. In that case, the -/// function used to spawn the thread (e.g. `std::thread::spawn`) will return -/// the error returned by the hook. +/// The hook will only be added for the current thread and is inherited by the threads it spawns. +/// In other words, adding a hook has no effect on already running threads (other than the current +/// thread) and the threads they might spawn in the future. /// /// Hooks can only be added, not removed. /// @@ -28,15 +50,15 @@ static SPAWN_HOOKS: RwLock< /// /// std::thread::add_spawn_hook(|_| { /// ..; // This will run in the parent (spawning) thread. -/// Ok(move || { +/// move || { /// ..; // This will run it the child (spawned) thread. -/// }) +/// } /// }); /// ``` /// /// # Example /// -/// A spawn hook can be used to initialize thread locals from the parent thread: +/// A spawn hook can be used to "inherit" a thread local from the parent thread: /// /// ``` /// #![feature(thread_spawn_hook)] @@ -47,13 +69,12 @@ static SPAWN_HOOKS: RwLock< /// static X: Cell = Cell::new(0); /// } /// +/// // This needs to be done once in the main thread before spawning any threads. /// std::thread::add_spawn_hook(|_| { /// // Get the value of X in the spawning thread. /// let value = X.get(); /// // Set the value of X in the newly spawned thread. -/// Ok(move || { -/// X.set(value); -/// }) +/// move || X.set(value) /// }); /// /// X.set(123); @@ -65,15 +86,17 @@ static SPAWN_HOOKS: RwLock< #[unstable(feature = "thread_spawn_hook", issue = "none")] pub fn add_spawn_hook(hook: F) where - F: 'static + Sync + Fn(&Thread) -> io::Result, + F: 'static + Sync + Fn(&Thread) -> G, G: 'static + Send + FnOnce(), { - SPAWN_HOOKS.write().unwrap_or_else(|e| e.into_inner()).push(Box::leak(Box::new( - move |thread: &Thread| -> io::Result<_> { - let f: Box = Box::new(hook(thread)?); - Ok(f) - }, - ))); + SPAWN_HOOKS.with(|h| { + let mut hooks = h.take(); + hooks.first = Some(Arc::new(SpawnHook { + hook: Box::new(move |thread| Box::new(hook(thread))), + next: hooks.first.take(), + })); + h.set(hooks); + }); } /// Runs all the spawn hooks. @@ -81,12 +104,41 @@ where /// Called on the parent thread. /// /// Returns the functions to be called on the newly spawned thread. -pub(super) fn run_spawn_hooks(thread: &Thread) -> io::Result>> { - SPAWN_HOOKS - .read() - .unwrap_or_else(|e| e.into_inner()) - .iter() - .rev() - .map(|hook| hook(thread)) - .collect() +pub(super) fn run_spawn_hooks(thread: &Thread) -> SpawnHookResults { + // Get a snapshot of the spawn hooks. + // (Increments the refcount to the first node.) + let hooks = SPAWN_HOOKS.with(|hooks| { + let snapshot = hooks.take(); + hooks.set(snapshot.clone()); + snapshot + }); + // Iterate over the hooks, run them, and collect the results in a vector. + let mut next: &Option> = &hooks.first; + let mut to_run = Vec::new(); + while let Some(hook) = next { + to_run.push((hook.hook)(thread)); + next = &hook.next; + } + // Pass on the snapshot of the hooks and the results to the new thread, + // which will then run SpawnHookResults::run(). + SpawnHookResults { hooks, to_run } +} + +/// The results of running the spawn hooks. +/// +/// This struct is sent to the new thread. +/// It contains the inherited hooks and the closures to be run. +pub(super) struct SpawnHookResults { + hooks: SpawnHooks, + to_run: Vec>, +} + +impl SpawnHookResults { + // This is run on the newly spawned thread, directly at the start. + pub(super) fn run(self) { + SPAWN_HOOKS.set(self.hooks); + for run in self.to_run { + run(); + } + } } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 00a0b55c6a9..47407df909b 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -141,9 +141,9 @@ pub fn test_main(args: &[String], tests: Vec, options: Option Date: Thu, 24 Oct 2024 11:19:02 +0200 Subject: Add thread Builder::no_hooks(). --- library/std/src/thread/mod.rs | 22 +++++++++++++++++++--- library/std/src/thread/spawnhook.rs | 9 +++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 79621e7fa6b..4a4c2c4b960 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -264,6 +264,8 @@ pub struct Builder { name: Option, // The size of the stack for the spawned thread in bytes stack_size: Option, + // Skip running and inheriting the thread spawn hooks + no_hooks: bool, } impl Builder { @@ -287,7 +289,7 @@ impl Builder { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { - Builder { name: None, stack_size: None } + Builder { name: None, stack_size: None, no_hooks: false } } /// Names the thread-to-be. Currently the name is used for identification @@ -343,6 +345,16 @@ impl Builder { self } + /// Disables running and inheriting [spawn hooks](add_spawn_hook). + /// + /// Use this if the parent thread is in no way relevant for the child thread. + /// For example, when lazily spawning threads for a thread pool. + #[unstable(feature = "thread_spawn_hook", issue = "none")] + pub fn no_hooks(mut self) -> Builder { + self.no_hooks = true; + self + } + /// Spawns a new thread by taking ownership of the `Builder`, and returns an /// [`io::Result`] to its [`JoinHandle`]. /// @@ -465,7 +477,7 @@ impl Builder { F: Send, T: Send, { - let Builder { name, stack_size } = self; + let Builder { name, stack_size, no_hooks } = self; let stack_size = stack_size.unwrap_or_else(|| { static MIN: AtomicUsize = AtomicUsize::new(0); @@ -491,7 +503,11 @@ impl Builder { None => Thread::new_unnamed(id), }; - let hooks = spawnhook::run_spawn_hooks(&my_thread); + let hooks = if no_hooks { + spawnhook::ChildSpawnHooks::default() + } else { + spawnhook::run_spawn_hooks(&my_thread) + }; let their_thread = my_thread.clone(); diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 9c4e9eb6aa1..b0732ae69c3 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -104,7 +104,7 @@ where /// Called on the parent thread. /// /// Returns the functions to be called on the newly spawned thread. -pub(super) fn run_spawn_hooks(thread: &Thread) -> SpawnHookResults { +pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks { // Get a snapshot of the spawn hooks. // (Increments the refcount to the first node.) let hooks = SPAWN_HOOKS.with(|hooks| { @@ -121,19 +121,20 @@ pub(super) fn run_spawn_hooks(thread: &Thread) -> SpawnHookResults { } // Pass on the snapshot of the hooks and the results to the new thread, // which will then run SpawnHookResults::run(). - SpawnHookResults { hooks, to_run } + ChildSpawnHooks { hooks, to_run } } /// The results of running the spawn hooks. /// /// This struct is sent to the new thread. /// It contains the inherited hooks and the closures to be run. -pub(super) struct SpawnHookResults { +#[derive(Default)] +pub(super) struct ChildSpawnHooks { hooks: SpawnHooks, to_run: Vec>, } -impl SpawnHookResults { +impl ChildSpawnHooks { // This is run on the newly spawned thread, directly at the start. pub(super) fn run(self) { SPAWN_HOOKS.set(self.hooks); -- cgit 1.4.1-3-g733a5 From 5a80b48fe17f8ea772125dbc5220a134b1b15c68 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 24 Oct 2024 11:37:35 +0200 Subject: Use Send + Sync for spawn hooks. --- library/std/src/thread/spawnhook.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index b0732ae69c3..f9a4a2e0da7 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -24,7 +24,7 @@ impl Drop for SpawnHooks { } struct SpawnHook { - hook: Box Box>, + hook: Box Box>, next: Option>, } @@ -86,7 +86,7 @@ struct SpawnHook { #[unstable(feature = "thread_spawn_hook", issue = "none")] pub fn add_spawn_hook(hook: F) where - F: 'static + Sync + Fn(&Thread) -> G, + F: 'static + Send + Sync + Fn(&Thread) -> G, G: 'static + Send + FnOnce(), { SPAWN_HOOKS.with(|h| { -- cgit 1.4.1-3-g733a5 From 24fec0d896ea160ce98113c9600d25f5db4d9827 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 12 Nov 2024 17:18:15 +0100 Subject: Add tracking issue. --- library/std/src/thread/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 4a4c2c4b960..2c2cc58a9dd 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -190,7 +190,7 @@ pub(crate) use current::{current_id, drop_current, set_current, try_current}; mod spawnhook; -#[unstable(feature = "thread_spawn_hook", issue = "none")] +#[unstable(feature = "thread_spawn_hook", issue = "132951")] pub use spawnhook::add_spawn_hook; //////////////////////////////////////////////////////////////////////////////// @@ -349,7 +349,7 @@ impl Builder { /// /// Use this if the parent thread is in no way relevant for the child thread. /// For example, when lazily spawning threads for a thread pool. - #[unstable(feature = "thread_spawn_hook", issue = "none")] + #[unstable(feature = "thread_spawn_hook", issue = "132951")] pub fn no_hooks(mut self) -> Builder { self.no_hooks = true; self -- cgit 1.4.1-3-g733a5 From 38b9a448c9a00ca25c6fca352273d819cf92dacb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 19 Nov 2024 15:19:13 +0100 Subject: Fix tracking issue. --- library/std/src/thread/spawnhook.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index f9a4a2e0da7..1513a5036cb 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -83,7 +83,7 @@ struct SpawnHook { /// assert_eq!(X.get(), 123); /// }).join().unwrap(); /// ``` -#[unstable(feature = "thread_spawn_hook", issue = "none")] +#[unstable(feature = "thread_spawn_hook", issue = "132951")] pub fn add_spawn_hook(hook: F) where F: 'static + Send + Sync + Fn(&Thread) -> G, -- cgit 1.4.1-3-g733a5 From b96f023dbd044e70eddd208cd21a295f62e5b28b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 19 Nov 2024 17:50:42 +0000 Subject: Address review comments. Co-authored-by: waffle --- library/std/src/thread/spawnhook.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index 1513a5036cb..b979db6bd60 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -1,4 +1,5 @@ use crate::cell::Cell; +use crate::iter; use crate::sync::Arc; use crate::thread::Thread; @@ -91,9 +92,10 @@ where { SPAWN_HOOKS.with(|h| { let mut hooks = h.take(); + let next = hooks.first.take(); hooks.first = Some(Arc::new(SpawnHook { hook: Box::new(move |thread| Box::new(hook(thread))), - next: hooks.first.take(), + next, })); h.set(hooks); }); @@ -113,12 +115,9 @@ pub(super) fn run_spawn_hooks(thread: &Thread) -> ChildSpawnHooks { snapshot }); // Iterate over the hooks, run them, and collect the results in a vector. - let mut next: &Option> = &hooks.first; - let mut to_run = Vec::new(); - while let Some(hook) = next { - to_run.push((hook.hook)(thread)); - next = &hook.next; - } + let to_run: Vec<_> = iter::successors(hooks.first.as_deref(), |hook| hook.next.as_deref()) + .map(|hook| (hook.hook)(thread)) + .collect(); // Pass on the snapshot of the hooks and the results to the new thread, // which will then run SpawnHookResults::run(). ChildSpawnHooks { hooks, to_run } -- cgit 1.4.1-3-g733a5 From 691796be03d77951982a86f4913994791ed4fb61 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 19 Nov 2024 18:53:39 +0100 Subject: Update doc comments for spawn hook. --- library/std/src/thread/spawnhook.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/thread/spawnhook.rs b/library/std/src/thread/spawnhook.rs index b979db6bd60..99b5ad9cb9f 100644 --- a/library/std/src/thread/spawnhook.rs +++ b/library/std/src/thread/spawnhook.rs @@ -3,8 +3,12 @@ use crate::iter; use crate::sync::Arc; use crate::thread::Thread; -// A thread local linked list of spawn hooks. crate::thread_local! { + /// A thread local linked list of spawn hooks. + /// + /// It is a linked list of Arcs, such that it can very cheaply be inhereted by spawned threads. + /// + /// (That technically makes it a set of linked lists with shared tails, so a linked tree.) static SPAWN_HOOKS: Cell = const { Cell::new(SpawnHooks { first: None }) }; } @@ -42,7 +46,7 @@ struct SpawnHook { /// /// Hooks can only be added, not removed. /// -/// The hooks will run in order, starting with the most recently added. +/// The hooks will run in reverse order, starting with the most recently added. /// /// # Usage /// -- cgit 1.4.1-3-g733a5 From d667dd56774686988b80d93d13391572e907231a Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 19:31:02 +0100 Subject: remove `TypingMode::from_param_env` in clippy --- src/tools/clippy/clippy_lints/src/dereference.rs | 15 +++--- src/tools/clippy/clippy_lints/src/derive.rs | 14 ++++-- .../clippy_lints/src/loops/explicit_iter_loop.rs | 8 ++-- .../src/needless_borrows_for_generic_args.rs | 6 +-- .../clippy_lints/src/needless_pass_by_value.rs | 11 +++-- src/tools/clippy/clippy_utils/src/lib.rs | 54 ++++++++++++---------- src/tools/clippy/clippy_utils/src/ty.rs | 37 ++++++--------- 7 files changed, 77 insertions(+), 68 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 9049739dddb..fce7f9985ea 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -15,6 +15,7 @@ use rustc_hir::{ self as hir, BindingMode, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TyKind, UnOp, }; +use rustc_hir::def_id::DefId; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults}; @@ -753,11 +754,10 @@ impl TyCoercionStability { fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self { match ty { DefinedTy::Hir(ty) => Self::for_hir_ty(ty), - DefinedTy::Mir(ty) => Self::for_mir_ty( + DefinedTy::Mir { def_site_def_id, ty } => Self::for_mir_ty( cx.tcx, - // FIXME(#132279): convert `DefinedTy` to use `TypingEnv` instead. - ty::TypingEnv::from_param_env(ty.param_env), - cx.tcx.instantiate_bound_regions_with_erased(ty.value), + def_site_def_id, + cx.tcx.instantiate_bound_regions_with_erased(ty), for_return, ), } @@ -824,12 +824,15 @@ impl TyCoercionStability { } } - fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self { + fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, def_site_def_id: Option, ty: Ty<'tcx>, for_return: bool) -> Self { let ty::Ref(_, mut ty, _) = *ty.kind() else { return Self::None; }; - ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + if let Some(def_id) = def_site_def_id { + let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); + ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + } loop { break match *ty.kind() { ty::Ref(_, ref_ty, _) => { diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 0db6a822ec0..3b6b3c89858 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -454,13 +454,13 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r && cx.tcx.is_diagnostic_item(sym::PartialEq, def_id) && !has_non_exhaustive_attr(cx.tcx, *adt) && !ty_implements_eq_trait(cx.tcx, ty, eq_trait_def_id) - && let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) + && let typing_env = typing_env_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id) && let Some(local_def_id) = adt.did().as_local() // If all of our fields implement `Eq`, we can implement `Eq` too && adt .all_fields() .map(|f| f.ty(cx.tcx, args)) - .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, None, &[])) + .all(|ty| implements_trait_with_env(cx.tcx, typing_env, ty, eq_trait_def_id, None, &[])) { span_lint_hir_and_then( cx, @@ -485,7 +485,7 @@ fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: De } /// Creates the `ParamEnv` used for the give type's derived `Eq` impl. -fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ParamEnv<'_> { +fn typing_env_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> { // Initial map from generic index to param def. // Vec<(param_def, needs_eq)> let mut params = tcx @@ -506,7 +506,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> } } - ParamEnv::new( + let param_env = ParamEnv::new( tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { ClauseKind::Trait(TraitPredicate { @@ -517,5 +517,9 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> }), )), Reveal::UserFacing, - ) + ); + ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env, + } } diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index 48318682f33..d999e1a0585 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -115,11 +115,11 @@ fn is_ref_iterable<'tcx>( .tcx .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output - && let param_env = cx.tcx.param_env(fn_id) - && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, Some(fn_id), &[]) + && let typing_env = ty::TypingEnv::non_body_analysis(cx.tcx, fn_id) + && implements_trait_with_env(cx.tcx, typing_env, req_self_ty, trait_id, Some(fn_id), &[]) && let Some(into_iter_ty) = - make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty]) - && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty) + make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym!(IntoIter), [req_self_ty]) + && let req_res_ty = normalize_with_regions(cx.tcx, typing_env, req_res_ty) && into_iter_ty == req_res_ty { let adjustments = typeck.expr_adjustments(self_arg); diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index 43b885fbd2c..9ebef531bc5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { && use_cx.same_ctxt && !use_cx.is_ty_unified && let use_node = use_cx.use_node(cx) - && let Some(DefinedTy::Mir(ty)) = use_node.defined_ty(cx) - && let ty::Param(ty) = *ty.value.skip_binder().kind() + && let Some(DefinedTy::Mir { def_site_def_id: _, ty }) = use_node.defined_ty(cx) + && let ty::Param(param_ty) = *ty.skip_binder().kind() && let Some((hir_id, fn_id, i)) = match use_node { ExprUseNode::MethodArg(_, _, 0) => None, ExprUseNode::MethodArg(hir_id, None, i) => cx @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { fn_id, cx.typeck_results().node_args(hir_id), i, - ty, + param_ty, expr, &self.msrv, ) diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index ad0ab148530..b65ec8c3c48 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -182,9 +182,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { && !is_copy(cx, ty) && ty.is_sized(cx.tcx, cx.typing_env()) && !allowed_traits.iter().any(|&t| { - implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, t, None, [Option::< - ty::GenericArg<'tcx>, - >::None]) + implements_trait_with_env_from_iter( + cx.tcx, + cx.typing_env(), + ty, + t, + None, + [None::>] + ) }) && !implements_borrow_trait && !all_borrowable_trait diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index f28e5c9ed0e..6408cc938cb 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -116,8 +116,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv, - ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, + self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, + Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; @@ -2712,9 +2712,17 @@ pub fn walk_to_expr_usage<'tcx, T>( pub enum DefinedTy<'tcx> { // Used for locals and closures defined within the function. Hir(&'tcx hir::Ty<'tcx>), - /// Used for function signatures, and constant and static values. This includes the `ParamEnv` - /// from the definition site. - Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>), + /// Used for function signatures, and constant and static values. The type is + /// in the context of its definition site. We also track the `def_id` of its + /// definition site. + /// + /// WARNING: As the `ty` in in the scope of the definition, not of the function + /// using it, you must be very careful with how you use it. Using it in the wrong + /// scope easily results in ICEs. + Mir { + def_site_def_id: Option, + ty: Binder<'tcx, Ty<'tcx>>, + }, } /// The context an expressions value is used in. @@ -2833,10 +2841,10 @@ impl<'tcx> ExprUseNode<'tcx> { pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option> { match *self { Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)), - Self::ConstStatic(id) => Some(DefinedTy::Mir( - cx.param_env - .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())), - )), + Self::ConstStatic(id) => Some(DefinedTy::Mir { + def_site_def_id: Some(id.def_id.to_def_id()), + ty: Binder::dummy(cx.tcx.type_of(id).instantiate_identity()), + }), Self::Return(id) => { if let Node::Expr(Expr { kind: ExprKind::Closure(c), @@ -2848,9 +2856,8 @@ impl<'tcx> ExprUseNode<'tcx> { FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)), } } else { - Some(DefinedTy::Mir( - cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()), - )) + let ty = cx.tcx.fn_sig(id).instantiate_identity().output(); + Some(DefinedTy::Mir { def_site_def_id: Some(id.def_id.to_def_id()), ty }) } }, Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) { @@ -2866,12 +2873,9 @@ impl<'tcx> ExprUseNode<'tcx> { .find(|f| f.name == field.ident.name) .map(|f| (adt, f)) }) - .map(|(adt, field_def)| { - DefinedTy::Mir( - cx.tcx - .param_env(adt.did()) - .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())), - ) + .map(|(adt, field_def)| DefinedTy::Mir { + def_site_def_id: Some(adt.did()), + ty: Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity()), }), _ => None, }, @@ -2880,17 +2884,19 @@ impl<'tcx> ExprUseNode<'tcx> { let (hir_ty, ty) = sig.input_with_hir(i)?; Some(match hir_ty { Some(hir_ty) => DefinedTy::Hir(hir_ty), - None => DefinedTy::Mir( - sig.predicates_id() - .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)) - .and(ty), - ), + None => DefinedTy::Mir { + def_site_def_id: sig.predicates_id(), + ty, + } }) }, Self::MethodArg(id, _, i) => { let id = cx.typeck_results().type_dependent_def_id(id)?; let sig = cx.tcx.fn_sig(id).skip_binder(); - Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i)))) + Some(DefinedTy::Mir { + def_site_def_id: Some(id), + ty: sig.input(i), + }) }, Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Other | Self::AddrOf(..) => None, } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index fff516b730d..3498606dfd3 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, UintTy, Upcast, VariantDef, VariantDiscr, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -226,7 +226,7 @@ pub fn implements_trait<'tcx>( trait_id: DefId, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, None, args.iter().map(|&x| Some(x))) + implements_trait_with_env_from_iter(cx.tcx, cx.typing_env(), ty, trait_id, None, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context. @@ -235,19 +235,19 @@ pub fn implements_trait<'tcx>( /// environment, used for checking const traits. pub fn implements_trait_with_env<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, callee_id: Option, args: &[GenericArg<'tcx>], ) -> bool { - implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) + implements_trait_with_env_from_iter(tcx, typing_env, ty, trait_id, callee_id, args.iter().map(|&x| Some(x))) } /// Same as `implements_trait_from_env` but takes the arguments as an iterator. pub fn implements_trait_with_env_from_iter<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, trait_id: DefId, callee_id: Option, @@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let args = args .into_iter() .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())) @@ -1239,12 +1239,12 @@ impl<'tcx> InteriorMut<'tcx> { pub fn make_normalized_projection_with_regions<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, container_id: DefId, assoc_ty: Symbol, args: impl IntoIterator>>, ) -> Option> { - fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { #[cfg(debug_assertions)] if let Some((i, arg)) = ty .args @@ -1261,10 +1261,8 @@ pub fn make_normalized_projection_with_regions<'tcx>( return None; } let cause = ObligationCause::dummy(); - match tcx - .infer_ctxt() - .build(TypingMode::from_param_env(param_env)) - .at(&cause, param_env) + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + match infcx.at(&cause, param_env) .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { Ok(ty) => Some(ty.value), @@ -1274,20 +1272,13 @@ pub fn make_normalized_projection_with_regions<'tcx>( }, } } - helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, args)?) + helper(tcx, typing_env, make_projection(tcx, container_id, assoc_ty, args)?) } -pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { +pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { let cause = ObligationCause::dummy(); - match tcx - .infer_ctxt() - .build(TypingMode::from_param_env(param_env)) - .at(&cause, param_env) - .query_normalize(ty) - { - Ok(ty) => ty.value, - Err(_) => ty, - } + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + infcx.at(&cause, param_env).query_normalize(ty).map_or(ty, |ty| ty.value) } /// Checks if the type is `core::mem::ManuallyDrop<_>` -- cgit 1.4.1-3-g733a5 From b9dea31ea96b6eef91ab26307b0870783d4931ef Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 19:32:52 +0100 Subject: `TypingMode::from_param_env` begone --- compiler/rustc_middle/src/ty/mod.rs | 6 ------ compiler/rustc_type_ir/src/infer_ctxt.rs | 14 -------------- 2 files changed, 20 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cddd6110c23..d1f8d1b0949 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1140,12 +1140,6 @@ pub struct TypingEnv<'tcx> { } impl<'tcx> TypingEnv<'tcx> { - // FIXME(#132279): This method should be removed but simplifies the - // transition. - pub fn from_param_env(param_env: ParamEnv<'tcx>) -> TypingEnv<'tcx> { - TypingEnv { typing_mode: TypingMode::from_param_env(param_env), param_env } - } - /// Create a typing environment with no where-clauses in scope /// where all opaque types and default associated items are revealed. /// diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 105ae76708b..b01d3dc5269 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -4,10 +4,8 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::fold::TypeFoldable; -use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; -use crate::solve::Reveal; use crate::{self as ty, Interner}; /// The current typing mode of an inference context. We unfortunately have some @@ -58,18 +56,6 @@ impl TypingMode { pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode { TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } } - - /// FIXME(#132279): Using this function is questionable as the `param_env` - /// does not track `defining_opaque_types` and whether we're in coherence mode. - /// Many uses of this function should also use a not-yet implemented typing mode - /// which reveals already defined opaque types in the future. This function will - /// get completely removed at some point. - pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode { - match param_env.reveal() { - Reveal::UserFacing => TypingMode::non_body_analysis(), - Reveal::All => TypingMode::PostAnalysis, - } - } } pub trait InferCtxtLike: Sized { -- cgit 1.4.1-3-g733a5 From 7a90e84f4d760cb49035f1446d4c6cfb3993aad2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 20:10:42 +0100 Subject: `InterpCx` store `TypingEnv` instead of a `ParamEnv` --- .../rustc_codegen_cranelift/src/intrinsics/mod.rs | 6 ++- compiler/rustc_codegen_ssa/src/mir/intrinsic.rs | 5 +- .../src/const_eval/eval_queries.rs | 50 ++++++++----------- .../rustc_const_eval/src/const_eval/machine.rs | 2 +- compiler/rustc_const_eval/src/const_eval/mod.rs | 8 +-- .../rustc_const_eval/src/const_eval/valtrees.rs | 25 +++++----- compiler/rustc_const_eval/src/interpret/call.rs | 58 +++++++++++----------- compiler/rustc_const_eval/src/interpret/cast.rs | 4 +- .../rustc_const_eval/src/interpret/eval_context.rs | 43 ++++++++-------- compiler/rustc_const_eval/src/interpret/intern.rs | 2 +- .../rustc_const_eval/src/interpret/intrinsics.rs | 9 ++-- compiler/rustc_const_eval/src/interpret/memory.rs | 4 +- .../rustc_const_eval/src/interpret/operator.rs | 2 +- compiler/rustc_const_eval/src/interpret/place.rs | 4 +- compiler/rustc_const_eval/src/interpret/stack.rs | 4 +- compiler/rustc_const_eval/src/interpret/step.rs | 3 +- .../rustc_const_eval/src/interpret/validity.rs | 13 +++-- compiler/rustc_const_eval/src/lib.rs | 7 ++- .../rustc_const_eval/src/util/caller_location.rs | 2 +- .../src/util/check_validity_requirement.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 4 +- compiler/rustc_middle/src/mir/interpret/queries.rs | 32 ++++++------ compiler/rustc_middle/src/query/keys.rs | 12 ----- compiler/rustc_middle/src/query/mod.rs | 6 +-- compiler/rustc_middle/src/ty/instance.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 3 +- .../rustc_mir_transform/src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 9 ++-- compiler/rustc_mir_transform/src/jump_threading.rs | 2 +- .../rustc_mir_transform/src/known_panics_lint.rs | 2 +- compiler/rustc_smir/src/rustc_smir/context.rs | 4 +- .../clippy/clippy_lints/src/non_copy_const.rs | 6 +-- .../miri/src/borrow_tracker/stacked_borrows/mod.rs | 6 +-- .../miri/src/borrow_tracker/tree_borrows/mod.rs | 10 ++-- src/tools/miri/src/eval.rs | 2 +- src/tools/miri/src/machine.rs | 2 +- 36 files changed, 167 insertions(+), 192 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index c663f6fc2d3..3318c0797ec 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -744,7 +744,11 @@ fn codegen_regular_intrinsic_call<'tcx>( let const_val = fx .tcx - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, source_info.span) + .const_eval_instance( + ty::TypingEnv::fully_monomorphized(), + instance, + source_info.span, + ) .unwrap(); let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty); ret.write_cvalue(fx, val); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index c35d0b90706..299b98c0a4f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -146,10 +146,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | sym::type_id | sym::type_name | sym::variant_count => { - let value = bx - .tcx() - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, span) - .unwrap(); + let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap(); OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) } sym::arith_offset => { 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 ca3ee6773a0..64331eea75c 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,7 +7,6 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::query::TyCtxtAt; -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, Ty, TyCtxt}; @@ -31,7 +30,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( cid: GlobalId<'tcx>, body: &'tcx mir::Body<'tcx>, ) -> InterpResult<'tcx, R> { - trace!(?ecx.param_env); + trace!(?ecx.typing_env); let tcx = *ecx.tcx; assert!( cid.promoted.is_some() @@ -126,14 +125,14 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>( tcx: TyCtxt<'tcx>, root_span: Span, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, can_access_mut_global: CanAccessMutGlobal, ) -> CompileTimeInterpCx<'tcx> { - debug!("mk_eval_cx: {:?}", param_env); + debug!("mk_eval_cx: {:?}", typing_env); InterpCx::new( tcx, root_span, - param_env, + typing_env, CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No), ) } @@ -142,11 +141,11 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>( /// Returns both the context and an `OpTy` that represents the constant. pub fn mk_eval_cx_for_const_val<'tcx>( tcx: TyCtxtAt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, ) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { - let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); + let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, typing_env, CanAccessMutGlobal::No); // FIXME: is it a problem to discard the error here? let op = ecx.const_val_to_op(val, ty, None).discard_err()?; Some((ecx, op)) @@ -221,7 +220,7 @@ pub(super) fn op_to_const<'tcx>( let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( - ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(), + ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env).kind(), ty::Str | ty::Slice(..), ), "`ConstValue::Slice` is for slice-tailed types only, but got {}", @@ -245,7 +244,7 @@ pub(super) fn op_to_const<'tcx>( pub(crate) fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, constant: ConstAlloc<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ConstValue<'tcx> { let cid = key.value; let def_id = cid.instance.def.def_id(); @@ -254,7 +253,7 @@ pub(crate) fn turn_into_const_value<'tcx>( let ecx = mk_eval_cx_to_read_const_val( tcx, tcx.def_span(key.value.instance.def_id()), - key.param_env, + key.typing_env, CanAccessMutGlobal::from(is_static), ); @@ -274,23 +273,16 @@ pub(crate) fn turn_into_const_value<'tcx>( #[instrument(skip(tcx), level = "debug")] pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // 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. - assert_eq!(key.param_env.reveal(), Reveal::All); - let typing_env = - ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: key.param_env }; - // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, typing_env); + let ty = key.value.instance.ty(tcx, key.typing_env); let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err( + return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err( |error| { let span = tcx.def_span(def_id); @@ -317,7 +309,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 }; - eval_in_interpreter(tcx, cid, ty::ParamEnv::reveal_all()) + eval_in_interpreter(tcx, cid, ty::TypingEnv::fully_monomorphized()) } pub trait InterpretationResult<'tcx> { @@ -342,16 +334,14 @@ impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> { #[instrument(skip(tcx), level = "debug")] pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, + key: ty::PseudoCanonicalInput<'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. - - assert_eq!(key.param_env.reveal(), Reveal::All); + // Const eval always happens in PostAnalysis mode . See the comment in + // `InterpCx::new` for more details. + debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis); if cfg!(debug_assertions) { // Make sure we format the instance even if we do not print it. // This serves as a regression test against an ICE on printing. @@ -362,13 +352,13 @@ pub fn eval_to_allocation_raw_provider<'tcx>( trace!("const eval: {:?} ({})", key, instance); } - eval_in_interpreter(tcx, key.value, key.param_env) + eval_in_interpreter(tcx, key.value, key.typing_env) } fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( tcx: TyCtxt<'tcx>, cid: GlobalId<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ) -> Result { let def = cid.instance.def.def_id(); let is_static = tcx.is_static(def); @@ -376,7 +366,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( let mut ecx = InterpCx::new( tcx, tcx.def_span(def), - param_env, + typing_env, // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts // they do not have to behave "as if" they were evaluated at runtime. // For consts however we want to ensure they behave "as if" they were evaluated at runtime, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 347b1557d87..db82050c73c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -667,7 +667,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { .is_some_and(|p| !p.immutable()) { // That next check is expensive, that's why we have all the guards above. - let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env()); + let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env); let place = ecx.ref_to_mplace(val)?; let new_place = if is_immutable { place.map_provenance(CtfeProvenance::as_immutable) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index d5012236c34..8cbdcd68e13 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -38,8 +38,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, ) -> Option> { - let param_env = ty::ParamEnv::reveal_all(); - let (ecx, op) = mk_eval_cx_for_const_val(tcx, param_env, val, ty)?; + let typing_env = ty::TypingEnv::fully_monomorphized(); + let (ecx, op) = mk_eval_cx_for_const_val(tcx, typing_env, val, ty)?; // We go to `usize` as we cannot allocate anything bigger anyway. let (field_count, variant, down) = match ty.kind() { @@ -76,10 +76,12 @@ pub fn tag_for_variant_provider<'tcx>( ) -> Option { assert!(ty.is_enum()); + // FIXME: This uses an empty `TypingEnv` even though + // it may be used by a generic CTFE. let ecx = InterpCx::new( tcx, ty.default_span(tcx), - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), crate::const_eval::DummyMachine, ); diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 64bedea3b3f..515028e6826 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -2,7 +2,6 @@ use rustc_abi::{BackendRepr, VariantIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; -use rustc_middle::ty::solve::Reveal; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::DUMMY_SP; @@ -229,16 +228,19 @@ fn create_valtree_place<'tcx>( /// Evaluates a constant and turns it into a type-level constant value. pub(crate) fn eval_to_valtree<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, cid: GlobalId<'tcx>, ) -> EvalToValTreeResult<'tcx> { - let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?; + // Const eval always happens in PostAnalysis mode . See the comment in + // `InterpCx::new` for more details. + debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis); + let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?; // FIXME Need to provide a span to `eval_to_valtree` let ecx = mk_eval_cx_to_read_const_val( tcx, DUMMY_SP, - param_env, + typing_env, // It is absolutely crucial for soundness that // we do not read from mutable memory. CanAccessMutGlobal::No, @@ -273,7 +275,8 @@ pub(crate) fn eval_to_valtree<'tcx>( #[instrument(skip(tcx), level = "debug", ret)] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, - param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, valtree: ty::ValTree<'tcx>, ) -> mir::ConstValue<'tcx> { // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s @@ -282,10 +285,6 @@ pub fn valtree_to_const_value<'tcx>( // the `ValTree` and using `place_projection` and `place_field` to // create inner `MPlace`s which are filled recursively. // FIXME Does this need an example? - let (param_env, ty) = param_env_ty.into_parts(); - debug_assert_eq!(param_env.reveal(), Reveal::All); - let typing_env = ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env }; - match *ty.kind() { ty::FnDef(..) => { assert!(valtree.unwrap_branch().is_empty()); @@ -299,10 +298,10 @@ pub fn valtree_to_const_value<'tcx>( ), } } - ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree), + ty::Pat(ty, _) => valtree_to_const_value(tcx, typing_env, ty, valtree), ty::Ref(_, inner_ty, _) => { let mut ecx = - mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No); let imm = valtree_to_ref(&mut ecx, valtree, inner_ty); let imm = ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap()); @@ -324,14 +323,14 @@ pub fn valtree_to_const_value<'tcx>( for (i, &inner_valtree) in branches.iter().enumerate() { let field = layout.field(&LayoutCx::new(tcx, typing_env), i); if !field.is_zst() { - return valtree_to_const_value(tcx, param_env.and(field.ty), inner_valtree); + return valtree_to_const_value(tcx, typing_env, field.ty, inner_valtree); } } bug!("could not find non-ZST field during in {layout:#?}"); } let mut ecx = - mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); + mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No); // Need to create a place for this valtree. let place = create_valtree_place(&mut ecx, layout, valtree); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 6cfe4b21907..ed4a1a9e647 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -215,7 +215,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Even if `ty` is normalized, the search for the unsized tail will project // to fields, which can yield non-normalized types. So we need to provide a // normalization function. - let normalize = |ty| self.tcx.normalize_erasing_regions(self.typing_env(), ty); + let normalize = |ty| self.tcx.normalize_erasing_regions(self.typing_env, ty); ty.ptr_metadata_ty(*self.tcx, normalize) }; return interp_ok(meta_ty(caller) == meta_ty(callee)); @@ -652,35 +652,35 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; // Obtain the underlying trait we are working on, and the adjusted receiver argument. - let (trait_, dyn_ty, adjusted_recv) = - if let ty::Dynamic(data, _, ty::DynStar) = receiver_place.layout.ty.kind() { - let recv = self.unpack_dyn_star(&receiver_place, data)?; + let (trait_, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) = + receiver_place.layout.ty.kind() + { + let recv = self.unpack_dyn_star(&receiver_place, data)?; - (data.principal(), recv.layout.ty, recv.ptr()) - } else { - // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. - // (For that reason we also cannot use `unpack_dyn_trait`.) - let receiver_tail = self - .tcx - .struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env()); - let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else { - span_bug!( - self.cur_span(), - "dynamic call on non-`dyn` type {}", - receiver_tail - ) - }; - assert!(receiver_place.layout.is_unsized()); - - // Get the required information from the vtable. - let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; - let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?; - - // It might be surprising that we use a pointer as the receiver even if this - // is a by-val case; this works because by-val passing of an unsized `dyn - // Trait` to a function is actually desugared to a pointer. - (receiver_trait.principal(), dyn_ty, receiver_place.ptr()) + (data.principal(), recv.layout.ty, recv.ptr()) + } else { + // Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. + // (For that reason we also cannot use `unpack_dyn_trait`.) + let receiver_tail = + self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env); + let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else { + span_bug!( + self.cur_span(), + "dynamic call on non-`dyn` type {}", + receiver_tail + ) }; + assert!(receiver_place.layout.is_unsized()); + + // Get the required information from the vtable. + let vptr = receiver_place.meta().unwrap_meta().to_pointer(self)?; + let dyn_ty = self.get_ptr_vtable_ty(vptr, Some(receiver_trait))?; + + // It might be surprising that we use a pointer as the receiver even if this + // is a by-val case; this works because by-val passing of an unsized `dyn + // Trait` to a function is actually desugared to a pointer. + (receiver_trait.principal(), dyn_ty, receiver_place.ptr()) + }; // Now determine the actual method to call. Usually we use the easy way of just // looking up the method at index `idx`. @@ -704,7 +704,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let concrete_method = Instance::expect_resolve_for_vtable( tcx, - self.typing_env(), + self.typing_env, def_id, instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), self.cur_span(), diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 2d1bb5c9551..c95e51f0a1f 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -83,7 +83,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::FnDef(def_id, args) => { let instance = ty::Instance::resolve_for_fn_ptr( *self.tcx, - self.typing_env(), + self.typing_env, def_id, args, ) @@ -384,7 +384,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx> { // A -> A conversion let (src_pointee_ty, dest_pointee_ty) = - self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.typing_env()); + self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.typing_env); match (src_pointee_ty.kind(), dest_pointee_ty.kind()) { (&ty::Array(_, length), &ty::Slice(_)) => { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 31ce1600ce7..42fdf32e91e 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1,10 +1,12 @@ +use std::assert_matches::debug_assert_matches; + use either::{Left, Right}; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::at::ToTrace; -use rustc_infer::traits::{ObligationCause, Reveal}; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ @@ -36,8 +38,9 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> { /// we are evaluating (if this is CTFE). pub tcx: TyCtxtAt<'tcx>, - /// Bounds in scope for polymorphic evaluations. - pub(crate) param_env: ty::ParamEnv<'tcx>, + /// The current context in case we're evaluating in a + /// polymorphic context. This always uses `ty::TypingMode::PostAnalysis` + pub typing_env: ty::TypingEnv<'tcx>, /// The virtual memory system. pub memory: Memory<'tcx, M>, @@ -68,7 +71,7 @@ where M: Machine<'tcx>, { fn typing_env(&self) -> ty::TypingEnv<'tcx> { - self.typing_env() + self.typing_env } } @@ -189,25 +192,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn new( tcx: TyCtxt<'tcx>, root_span: Span, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, machine: M, ) -> Self { + // Const eval always happens in post analysis 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. We also use MIR bodies whose opaque types have + // already been revealed, so we'd be able to at least partially observe the hidden types anyways. + debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis); InterpCx { machine, tcx: tcx.at(root_span), - param_env, + typing_env, memory: Memory::new(), recursion_limit: tcx.recursion_limit(), } } - /// During CTFE we're always in `PostAnalysis` mode. - #[inline(always)] - pub fn typing_env(&self) -> ty::TypingEnv<'tcx> { - debug_assert_eq!(self.param_env.reveal(), Reveal::All); - ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: self.param_env } - } - /// Returns the span of the currently executed statement/terminator. /// This is the span typically used for error reporting. #[inline(always)] @@ -250,7 +251,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline] pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(*self.tcx, self.typing_env()) + ty.is_freeze(*self.tcx, self.typing_env) } pub fn load_mir( @@ -296,7 +297,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .instance .try_instantiate_mir_and_normalize_erasing_regions( *self.tcx, - self.typing_env(), + self.typing_env, ty::EarlyBinder::bind(value), ) .map_err(|_| ErrorHandled::TooGeneric(self.cur_span())) @@ -309,9 +310,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { args: GenericArgsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { trace!("resolve: {:?}, {:#?}", def, args); - trace!("param_env: {:#?}", self.param_env); + trace!("typing_env: {:#?}", self.typing_env); trace!("args: {:#?}", args); - match ty::Instance::try_resolve(*self.tcx, self.typing_env(), def, args) { + match ty::Instance::try_resolve(*self.tcx, self.typing_env, def, args) { Ok(Some(instance)) => interp_ok(instance), Ok(None) => throw_inval!(TooGeneric), @@ -332,7 +333,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return true; } // Slow path: spin up an inference context to check if these traits are sufficiently equal. - let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env()); + let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy_with_span(self.cur_span()); // equate the two trait refs after normalization @@ -564,10 +565,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let val = if self.tcx.is_static(gid.instance.def_id()) { let alloc_id = self.tcx.reserve_and_set_static_alloc(gid.instance.def_id()); - let ty = instance.ty(self.tcx.tcx, self.typing_env()); + let ty = instance.ty(self.tcx.tcx, self.typing_env); mir::ConstAlloc { alloc_id, ty } } else { - self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.param_env.and(gid)))? + self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(self.typing_env.as_query_input(gid)))? }; self.raw_const_to_mplace(val) } @@ -579,7 +580,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| { - let const_val = val.eval(*ecx.tcx, ecx.typing_env(), span).map_err(|err| { + let const_val = val.eval(*ecx.tcx, ecx.typing_env, span).map_err(|err| { if M::ALL_CONSTS_ARE_PRECHECKED { match err { ErrorHandled::TooGeneric(..) => {}, diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 2d695688ae5..0cbb3b157f3 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -165,7 +165,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval InternKind::Static(Mutability::Not) => { ( // Outermost allocation is mutable if `!Freeze`. - if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env()) { + if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) { Mutability::Not } else { Mutability::Mut diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index c8859ab3e88..a79923e8555 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -34,13 +34,12 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll /// inside an `InterpCx` and instead have their value computed directly from rustc internal info. pub(crate) fn eval_nullary_intrinsic<'tcx>( tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, ) -> InterpResult<'tcx, ConstValue<'tcx>> { let tp_ty = args.type_at(0); let name = tcx.item_name(def_id); - let typing_env = ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env }; interp_ok(match name { sym::type_name => { ensure_monomorphic_enough(tcx, tp_ty)?; @@ -152,8 +151,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::type_name => Ty::new_static_str(self.tcx.tcx), _ => bug!(), }; - let val = - self.ctfe_query(|tcx| tcx.const_eval_global_id(self.param_env, gid, tcx.span))?; + let val = self + .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?; self.copy_op(&val, dest)?; } @@ -358,7 +357,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let should_panic = !self .tcx - .check_validity_requirement((requirement, self.typing_env().as_query_input(ty))) + .check_validity_requirement((requirement, self.typing_env.as_query_input(ty))) .map_err(|_| err_inval!(TooGeneric))?; if should_panic { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9bae9c4b310..277d293597a 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -859,8 +859,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // # Global allocations if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { - let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env()); - let mutbl = global_alloc.mutability(*self.tcx, self.typing_env()); + let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); + let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 201f1b5dc62..1fa5dcbd24f 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -533,7 +533,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } OffsetOf(fields) => { let val = - self.tcx.offset_of_subfield(self.typing_env(), layout, fields.iter()).bytes(); + self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes(); ImmTy::from_uint(val, usize_layout()) } UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx), diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 13fcccca76b..2beec544fad 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -540,7 +540,7 @@ where )?; if !mir_assign_valid_types( *self.tcx, - self.typing_env(), + self.typing_env, self.layout_of(normalized_place_ty)?, place.layout, ) { @@ -871,7 +871,7 @@ where // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. let layout_compat = - mir_assign_valid_types(*self.tcx, self.typing_env(), src.layout(), dest.layout()); + mir_assign_valid_types(*self.tcx, self.typing_env, src.layout(), dest.layout()); if !allow_transmute && !layout_compat { span_bug!( self.cur_span(), diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 037c1a233ee..8ce11c71b8b 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -379,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { for &const_ in body.required_consts() { let c = self.instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?; - c.eval(*self.tcx, self.typing_env(), const_.span).map_err(|err| { + c.eval(*self.tcx, self.typing_env, const_.span).map_err(|err| { err.emit_note(*self.tcx); err })?; @@ -596,7 +596,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return interp_ok(layout); } - let layout = from_known_layout(self.tcx, self.typing_env(), layout, || { + let layout = from_known_layout(self.tcx, self.typing_env, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index d4525243642..98aca37e73e 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -418,8 +418,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .collect::>>()?; let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); - let fn_sig = - self.tcx.normalize_erasing_late_bound_regions(self.typing_env(), fn_sig_binder); + let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.typing_env, fn_sig_binder); let extra_args = &args[fn_sig.inputs().len()..]; let extra_args = self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty)); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 9ff24a01689..273eaf42d87 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -448,7 +448,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { meta: MemPlaceMeta, pointee: TyAndLayout<'tcx>, ) -> InterpResult<'tcx> { - let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env()); + let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env); match tail.kind() { ty::Dynamic(data, _, ty::Dyn) => { let vtable = meta.unwrap_meta().to_pointer(self.ecx)?; @@ -568,7 +568,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); }; let (size, _align) = - global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env()); + global_alloc.size_and_align(*self.ecx.tcx, self.ecx.typing_env); if let GlobalAlloc::Static(did) = global_alloc { let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { @@ -619,7 +619,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; // Determine what it actually points to. let alloc_actual_mutbl = - global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env()); + global_alloc.mutability(*self.ecx.tcx, self.ecx.typing_env); // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not @@ -848,7 +848,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { let tcx = *self.ecx.tcx; // Everything must be already interned. - let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.typing_env()); + let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.typing_env); if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) { assert_eq!(alloc.mutability, mutbl); } @@ -955,7 +955,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ) -> Cow<'e, RangeSet> { assert!(layout.ty.is_union()); assert!(layout.is_sized(), "there are no unsized unions"); - let layout_cx = LayoutCx::new(*ecx.tcx, ecx.typing_env()); + let layout_cx = LayoutCx::new(*ecx.tcx, ecx.typing_env); return M::cached_union_data_range(ecx, layout.ty, || { let mut out = RangeSet(Vec::new()); union_data_range_uncached(&layout_cx, layout, Size::ZERO, &mut out); @@ -1085,8 +1085,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, ) -> InterpResult<'tcx> { // Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory. if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) { - if !val.layout.is_zst() - && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env()) + if !val.layout.is_zst() && !val.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.typing_env) { if !self.in_mutable_memory(val) { throw_validation_failure!(self.path, UnsafeCellInImmutable); diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 527236b2c22..2a7408f1c70 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -40,14 +40,13 @@ pub fn provide(providers: &mut Providers) { providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; 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(); - const_eval::eval_to_valtree(tcx, param_env, raw) + providers.eval_to_valtree = |tcx, ty::PseudoCanonicalInput { typing_env, value }| { + const_eval::eval_to_valtree(tcx, typing_env, value) }; providers.hooks.try_destructure_mir_constant_for_user_output = const_eval::try_destructure_mir_constant_for_user_output; providers.valtree_to_const_val = |tcx, (ty, valtree)| { - const_eval::valtree_to_const_value(tcx, ty::ParamEnv::reveal_all().and(ty), valtree) + const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), ty, valtree) }; providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 7f4c36835e4..9bf16d4fe16 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -60,7 +60,7 @@ pub(crate) fn const_caller_location_provider( let mut ecx = mk_eval_cx_to_read_const_val( tcx.tcx, tcx.span, - ty::ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), CanAccessMutGlobal::No, ); diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 1afc910ce8f..651a797e97c 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -49,7 +49,7 @@ fn check_validity_requirement_strict<'tcx>( ) -> Result> { let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error); - let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.typing_env.param_env, machine); + let mut cx = InterpCx::new(cx.tcx(), rustc_span::DUMMY_SP, cx.typing_env, machine); let allocated = cx .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 5830636c6e8..629cca88043 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -188,8 +188,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) { DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all(); - tcx.ensure().eval_to_const_value_raw(param_env.and(cid)); + let typing_env = ty::TypingEnv::fully_monomorphized(); + tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid)); } _ => (), } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 7092f87a7d1..6eeafe18b35 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -25,8 +25,8 @@ impl<'tcx> TyCtxt<'tcx> { let args = GenericArgs::identity_for_item(self, def_id); let instance = ty::Instance::new(def_id, args); let cid = GlobalId { instance, promoted: None }; - let param_env = self.param_env(def_id).with_reveal_all_normalized(self); - self.const_eval_global_id(param_env, cid, DUMMY_SP) + let typing_env = ty::TypingEnv::post_analysis(self, def_id); + self.const_eval_global_id(typing_env, cid, DUMMY_SP) } /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts @@ -41,8 +41,8 @@ impl<'tcx> TyCtxt<'tcx> { let args = GenericArgs::identity_for_item(self, def_id); let instance = ty::Instance::new(def_id, args); let cid = GlobalId { instance, promoted: None }; - let param_env = self.param_env(def_id).with_reveal_all_normalized(self); - let inputs = self.erase_regions(param_env.and(cid)); + let typing_env = ty::TypingEnv::post_analysis(self, def_id); + let inputs = self.erase_regions(typing_env.as_query_input(cid)); self.eval_to_allocation_raw(inputs) } @@ -76,7 +76,7 @@ impl<'tcx> TyCtxt<'tcx> { match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: ct.promoted }; - self.const_eval_global_id(typing_env.param_env, cid, span) + self.const_eval_global_id(typing_env, cid, span) } // For errors during resolution, we deliberately do not point at the usage site of the constant, // since for these errors the place the constant is used shouldn't matter. @@ -105,7 +105,7 @@ impl<'tcx> TyCtxt<'tcx> { match ty::Instance::try_resolve(self, typing_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None }; - self.const_eval_global_id_for_typeck(typing_env.param_env, cid, span).inspect(|_| { + self.const_eval_global_id_for_typeck(typing_env, cid, span).inspect(|_| { // We are emitting the lint here instead of in `is_const_evaluatable` // as we normalize obligations before checking them, and normalization // uses this function to evaluate this constant. @@ -144,24 +144,25 @@ impl<'tcx> TyCtxt<'tcx> { pub fn const_eval_instance( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, instance: ty::Instance<'tcx>, span: Span, ) -> EvalToConstValueResult<'tcx> { - self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) + self.const_eval_global_id(typing_env, GlobalId { instance, promoted: None }, span) } /// Evaluate a constant to a `ConstValue`. #[instrument(skip(self), level = "debug")] pub fn const_eval_global_id( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, cid: GlobalId<'tcx>, span: Span, ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid)); + let inputs = + self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid)); if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span)) @@ -174,13 +175,14 @@ impl<'tcx> TyCtxt<'tcx> { #[instrument(skip(self), level = "debug")] pub fn const_eval_global_id_for_typeck( self, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, cid: GlobalId<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.erase_regions(param_env.with_reveal_all_normalized(self).and(cid)); + let inputs = + self.erase_regions(typing_env.with_reveal_all_normalized(self).as_query_input(cid)); debug!(?inputs); if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. @@ -202,12 +204,12 @@ impl<'tcx> TyCtxtEnsure<'tcx> { // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self.tcx, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new(def_id, self.tcx.erase_regions(args)); let cid = GlobalId { instance, promoted: None }; - let param_env = self.tcx.param_env(def_id).with_reveal_all_normalized(self.tcx); + let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = self.tcx.erase_regions(param_env.and(cid)); + let inputs = self.tcx.erase_regions(typing_env.as_query_input(cid)); self.eval_to_const_value_raw(inputs) } } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index d2fab8e78d5..8fd99303622 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -456,18 +456,6 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { } } -impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { - type Cache = DefaultCache; - - fn default_span(&self, tcx: TyCtxt<'_>) -> Span { - self.value.default_span(tcx) - } - - fn ty_def_id(&self) -> Option { - self.value.ty_def_id() - } -} - impl<'tcx, T: Key> Key for ty::PseudoCanonicalInput<'tcx, T> { type Cache = DefaultCache; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b8291e8a352..9ae519dfe7e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1095,7 +1095,7 @@ rustc_queries! { /// Evaluates a constant and returns the computed allocation. /// /// **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>>) + query eval_to_allocation_raw(key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>) -> EvalToAllocationRawResult<'tcx> { desc { |tcx| "const-evaluating + checking `{}`", @@ -1121,7 +1121,7 @@ rustc_queries! { /// /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + query eval_to_const_value_raw(key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>) -> EvalToConstValueResult<'tcx> { desc { |tcx| "simplifying constant for the type system `{}`", @@ -1133,7 +1133,7 @@ rustc_queries! { /// Evaluate a constant and convert it to a type level constant or /// return `None` if that is not possible. query eval_to_valtree( - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>> + key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>> ) -> EvalToValTreeResult<'tcx> { desc { "evaluating type-level constant" } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index d42b6be4787..dab3e18de33 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -537,9 +537,7 @@ impl<'tcx> Instance<'tcx> { // All regions in the result of this query are erased, so it's // fine to erase all of the input regions. - let typing_env = tcx.erase_regions(typing_env); - let args = tcx.erase_regions(args); - tcx.resolve_instance_raw(typing_env.as_query_input((def_id, args))) + tcx.resolve_instance_raw(tcx.erase_regions(typing_env.as_query_input((def_id, args)))) } pub fn expect_resolve( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d1f8d1b0949..3078209a068 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1186,7 +1186,6 @@ impl<'tcx> TypingEnv<'tcx> { where T: TypeVisitable>, { - debug_assert!(!value.has_infer()); // FIXME(#132279): We should assert that the value does not contain any placeholders // as these placeholders are also local to the current inference context. However, we // currently use pseudo-canonical queries in the trait solver which replaces params with @@ -1209,7 +1208,7 @@ impl<'tcx> TypingEnv<'tcx> { /// This should be created by using `infcx.pseudo_canonicalize_query(param_env, value)` /// or by using `typing_env.as_query_input(value)`. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable)] +#[derive(HashStable, TypeVisitable, TypeFoldable)] pub struct PseudoCanonicalInput<'tcx, T> { pub typing_env: TypingEnv<'tcx>, pub value: T, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 500515bc3cc..26480be29f3 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { map, tcx, local_decls: &body.local_decls, - ecx: InterpCx::new(tcx, DUMMY_SP, typing_env.param_env, DummyMachine), + ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), typing_env, } } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 5150cb752bd..b3d9af37204 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -125,8 +125,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { // Clone dominators because we need them while mutating the body. let dominators = body.basic_blocks.dominators().clone(); - let mut state = - VnState::new(tcx, body, typing_env.param_env, &ssa, dominators, &body.local_decls); + let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls); ssa.for_each_assignment_mut( body.basic_blocks.as_mut_preserves_cfg(), |local, value, location| { @@ -266,7 +265,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn new( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, + typing_env: ty::TypingEnv<'tcx>, ssa: &'body SsaLocals, dominators: Dominators, local_decls: &'body LocalDecls<'tcx>, @@ -280,7 +279,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { + 4 * body.basic_blocks.len(); VnState { tcx, - ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), + ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), local_decls, locals: IndexVec::from_elem(None, local_decls), rev_locals: IndexVec::with_capacity(num_values), @@ -295,7 +294,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } fn typing_env(&self) -> ty::TypingEnv<'tcx> { - self.ecx.typing_env() + self.ecx.typing_env } #[instrument(level = "trace", skip(self), ret)] diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 71a843a785c..5c2c36db0f7 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -82,7 +82,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { let mut finder = TOFinder { tcx, typing_env, - ecx: InterpCx::new(tcx, DUMMY_SP, typing_env.param_env, DummyMachine), + ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), body, arena, map: Map::new(tcx, body, Some(MAX_PLACES)), diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 67afd19aa73..53e282e9b46 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -183,7 +183,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // to runtime, so we have to manually specify the correct typing mode. let typing_env = ty::TypingEnv::post_analysis(tcx, body.source.def_id()); let can_const_prop = CanConstProp::check(tcx, typing_env, body); - let ecx = InterpCx::new(tcx, tcx.def_span(def_id), typing_env.param_env, DummyMachine); + let ecx = InterpCx::new(tcx, tcx.def_span(def_id), typing_env, DummyMachine); ConstPropagator { ecx, diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index b19adf321c3..9025b47c422 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; use rustc_middle::ty::{ - GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, + GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, }; use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; @@ -713,7 +713,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let instance = tables.instances[def]; let tcx = tables.tcx; let result = tcx.const_eval_instance( - ParamEnv::reveal_all(), + ty::TypingEnv::fully_monomorphized(), instance, tcx.def_span(instance.def_id()), ); diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 57fa4797c5e..5416e00fe0c 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -270,8 +270,8 @@ impl<'tcx> NonCopyConst<'tcx> { instance, promoted: None, }; - let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx); - let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, DUMMY_SP); + let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id); + let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP); Self::is_value_unfrozen_raw(cx, result, ty) } @@ -294,7 +294,7 @@ impl<'tcx> NonCopyConst<'tcx> { instance, promoted: None, }; - tcx.const_eval_global_id_for_typeck(typing_env.param_env, cid, span) + tcx.const_eval_global_id_for_typeck(typing_env, cid, span) }, Ok(None) => Err(ErrorHandled::TooGeneric(span)), Err(err) => Err(ErrorHandled::Reported(err.into(), span)), diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index f46557ac630..9627447b342 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -70,7 +70,7 @@ impl NewPermission { access: None, protector: None, } - } else if pointee.is_unpin(*cx.tcx, cx.typing_env()) { + } else if pointee.is_unpin(*cx.tcx, cx.typing_env) { // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`. NewPermission::Uniform { perm: Permission::Unique, @@ -128,7 +128,7 @@ impl NewPermission { fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). let pointee = ty.builtin_deref(true).unwrap(); - if pointee.is_unpin(*cx.tcx, cx.typing_env()) { + if pointee.is_unpin(*cx.tcx, cx.typing_env) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). NewPermission::Uniform { @@ -607,7 +607,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { match new_perm { NewPermission::Uniform { perm, .. } => write!(kind_str, "{perm:?} permission").unwrap(), - NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env()) => + NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env) => write!(kind_str, "{freeze_perm:?} permission").unwrap(), NewPermission::FreezeSensitive { freeze_perm, nonfreeze_perm, .. } => write!(kind_str, "{freeze_perm:?}/{nonfreeze_perm:?} permission for frozen/non-frozen parts").unwrap(), diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 8f8e29846c9..61a2e2bc8d9 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -131,8 +131,8 @@ impl<'tcx> NewPermission { kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>, ) -> Option { - let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); - let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env()); + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env); + let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env); let is_protected = kind == RetagKind::FnEntry; // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`, // interior mutability and protectors interact poorly. @@ -163,10 +163,10 @@ impl<'tcx> NewPermission { zero_size: bool, ) -> Option { let pointee = ty.builtin_deref(true).unwrap(); - pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { + pointee.is_unpin(*cx.tcx, cx.typing_env).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. - let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env()); + let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env); let protected = kind == RetagKind::FnEntry; let initial_state = Permission::new_reserved(ty_is_freeze, protected); Self { @@ -520,7 +520,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Note: if we were to inline `new_reserved` below we would find out that // `ty_is_freeze` is eventually unused because it appears in a `ty_is_freeze || true`. // We are nevertheless including it here for clarity. - let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); + let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env); // Retag it. With protection! That is the entire point. let new_perm = NewPermission { initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true), diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 5ec497ef0ea..85591a0b370 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -273,7 +273,7 @@ pub fn create_ecx<'tcx>( let mut ecx = InterpCx::new( tcx, rustc_span::DUMMY_SP, - typing_env.param_env, + typing_env, MiriMachine::new(config, layout_cx) ); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 9c1951ec87a..3ab606e5847 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1128,7 +1128,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let info = ecx.get_alloc_info(alloc_id); let def_ty = ecx.tcx.type_of(def_id).instantiate_identity(); let extern_decl_layout = ecx.tcx.layout_of( - ecx.typing_env().as_query_input(def_ty) + ecx.typing_env.as_query_input(def_ty) ).unwrap(); if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align { throw_unsup_format!( -- cgit 1.4.1-3-g733a5 From d61effe58fb54e4adfcfe41bbf6536b5a7cdd1da Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 20:20:39 +0100 Subject: resolve_instance: stop relying on `Reveal` --- compiler/rustc_ty_utils/src/instance.rs | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 84fc03a8f13..29fc92e1f2f 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -13,7 +13,7 @@ use rustc_span::sym; use rustc_trait_selection::traits; use rustc_type_ir::ClosureKind; use tracing::debug; -use traits::{Reveal, translate_args}; +use traits::translate_args; use crate::errors::UnexpectedFnPtrAssociatedItem; @@ -133,18 +133,6 @@ fn resolve_associated_item<'tcx>( bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); }); - let typing_env = typing_env.with_reveal_all_normalized(tcx); - let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args); - let args = translate_args( - &infcx, - param_env, - impl_data.impl_def_id, - args, - leaf_def.defining_node, - ); - let args = infcx.tcx.erase_regions(args); - // Since this is a trait item, we need to see if the item is either a trait default item // or a specialization because we can't resolve those unless we can `Reveal::All`. // NOTE: This should be kept in sync with the similar code in @@ -157,16 +145,28 @@ fn resolve_associated_item<'tcx>( // and the obligation is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - if param_env.reveal() == Reveal::All { - !trait_ref.still_further_specializable() - } else { - false + match typing_env.typing_mode { + ty::TypingMode::Coherence + | ty::TypingMode::Analysis { defining_opaque_types: _ } => false, + ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(), } }; if !eligible { return Ok(None); } + let typing_env = typing_env.with_reveal_all_normalized(tcx); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args); + let args = translate_args( + &infcx, + param_env, + impl_data.impl_def_id, + args, + leaf_def.defining_node, + ); + let args = infcx.tcx.erase_regions(args); + // HACK: We may have overlapping `dyn Trait` built-in impls and // user-provided blanket impls. Detect that case here, and return // ambiguity. -- cgit 1.4.1-3-g733a5 From 002efeb72ac465cf04660537ca902172ab0e491b Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 19 Nov 2024 21:11:55 +0100 Subject: additional `TypingEnv` cleanups --- compiler/rustc_codegen_ssa/src/base.rs | 7 ++++--- compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 6 +++--- compiler/rustc_middle/src/mir/mod.rs | 5 +---- compiler/rustc_mir_transform/src/instsimplify.rs | 14 ++++---------- compiler/rustc_symbol_mangling/src/v0.rs | 6 +++--- compiler/rustc_trait_selection/src/traits/mod.rs | 4 ++-- compiler/rustc_trait_selection/src/traits/vtable.rs | 7 +++---- 7 files changed, 20 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c8b3b30218a..27c9cb0b31e 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -22,7 +22,7 @@ use rustc_middle::mir::BinOp; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; @@ -119,7 +119,8 @@ pub fn validate_trivial_unsize<'tcx>( ) -> bool { match (source_data.principal(), target_data.principal()) { (Some(hr_source_principal), Some(hr_target_principal)) => { - let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let universe = infcx.universe(); let ocx = ObligationCtxt::new(&infcx); infcx.enter_forall(hr_target_principal, |target_principal| { @@ -130,7 +131,7 @@ pub fn validate_trivial_unsize<'tcx>( ); let Ok(()) = ocx.eq_trace( &ObligationCause::dummy(), - ty::ParamEnv::reveal_all(), + param_env, ToTrace::to_trace( &ObligationCause::dummy(), hr_target_principal, 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 77c324183c3..8a051e34f82 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1193,9 +1193,9 @@ fn compare_self_type<'tcx>( ty::AssocItemContainer::Trait => tcx.types.self_param, }; let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0); - let param_env = ty::ParamEnv::reveal_all(); - - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); + let (infcx, param_env) = tcx + .infer_ctxt() + .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, method.def_id)); let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 425cb059e57..e2379f282ec 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -459,10 +459,7 @@ impl<'tcx> Body<'tcx> { typing_mode: ty::TypingMode::non_body_analysis(), param_env: tcx.param_env(self.source.def_id()), }, - MirPhase::Runtime(_) => TypingEnv { - typing_mode: ty::TypingMode::PostAnalysis, - param_env: tcx.param_env_reveal_all_normalized(self.source.def_id()), - }, + MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()), } } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index b80abcca969..3352d583f2c 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -6,7 +6,7 @@ use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, layout}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout}; use rustc_span::sym; use rustc_span::symbol::Symbol; @@ -34,7 +34,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { let ctx = InstSimplifyContext { tcx, local_decls: &body.local_decls, - param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()), + typing_env: body.typing_env(tcx), }; let preserve_ub_checks = attr::contains_name(tcx.hir().krate_attrs(), sym::rustc_preserve_ub_checks); @@ -66,13 +66,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { struct InstSimplifyContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, - param_env: ParamEnv<'tcx>, -} - -impl<'tcx> InstSimplifyContext<'_, 'tcx> { - fn typing_env(&self) -> ty::TypingEnv<'tcx> { - ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: self.param_env } - } + typing_env: ty::TypingEnv<'tcx>, } impl<'tcx> InstSimplifyContext<'_, 'tcx> { @@ -354,7 +348,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } let known_is_valid = - intrinsic_assert_panics(self.tcx, self.typing_env(), args[0], intrinsic_name); + intrinsic_assert_panics(self.tcx, self.typing_env, args[0], intrinsic_name); match known_is_valid { // We don't know the layout or it's not validity assertion at all, don't touch it None => {} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 94f51b87cff..dcbc5f0f76d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -233,11 +233,11 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { let key = self.tcx.def_key(impl_def_id); let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; - let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id); + let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id); if !args.is_empty() { - param_env = EarlyBinder::bind(param_env).instantiate(self.tcx, args); + typing_env.param_env = + EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args); } - let typing_env = ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env }; match &mut impl_trait_ref { Some(impl_trait_ref) => { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c0603c06d42..80cef690028 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -698,8 +698,8 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( /// used during analysis. pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec>) -> bool { debug!("impossible_predicates(predicates={:?})", predicates); - let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); - let param_env = ty::ParamEnv::reveal_all(); + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); for predicate in predicates { diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 8352d31d13a..b5bc8364c7b 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -9,8 +9,7 @@ use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, - VtblEntry, + self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry, }; use rustc_span::{DUMMY_SP, Span, sym}; use smallvec::{SmallVec, smallvec}; @@ -442,8 +441,8 @@ fn trait_refs_are_compatible<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); - let param_env = ty::ParamEnv::reveal_all(); + let (infcx, param_env) = + tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let ocx = ObligationCtxt::new(&infcx); let hr_source_principal = ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal); -- cgit 1.4.1-3-g733a5 From df94818366648595e9cf6fa4fa7d061a5adfd780 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Nov 2024 15:32:11 +0100 Subject: lints_that_dont_need_to_run: never skip future-compat-reported lints --- compiler/rustc_lint/src/levels.rs | 22 ++++++++++++---------- compiler/rustc_lint_defs/src/lib.rs | 14 ++++++++++++++ compiler/rustc_middle/src/lint.rs | 7 +------ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 97a95787422..4b1dafbdbee 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -123,17 +123,19 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { let dont_need_to_run: FxIndexSet = store .get_lints() .into_iter() + .filter(|lint| { + // Lints that show up in future-compat reports must always be run. + let has_future_breakage = + lint.future_incompatible.is_some_and(|fut| fut.reason.has_future_breakage()); + !has_future_breakage && !lint.eval_always + }) .filter_map(|lint| { - if !lint.eval_always { - let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); - if matches!(lint_level, (Level::Allow, ..)) - || (matches!(lint_level, (.., LintLevelSource::Default))) - && lint.default_level(tcx.sess.edition()) == Level::Allow - { - Some(LintId::of(lint)) - } else { - None - } + let lint_level = map.lint_level_id_at_node(tcx, LintId::of(lint), CRATE_HIR_ID); + if matches!(lint_level, (Level::Allow, ..)) + || (matches!(lint_level, (.., LintLevelSource::Default))) + && lint.default_level(tcx.sess.edition()) == Level::Allow + { + Some(LintId::of(lint)) } else { None } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index eac4afee050..c74fceeedba 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -466,6 +466,20 @@ impl FutureIncompatibilityReason { | FutureIncompatibilityReason::Custom(_) => None, } } + + pub fn has_future_breakage(self) -> bool { + match self { + FutureIncompatibilityReason::FutureReleaseErrorReportInDeps => true, + + FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps + | FutureIncompatibilityReason::FutureReleaseSemanticsChange + | FutureIncompatibilityReason::EditionError(_) + | FutureIncompatibilityReason::EditionSemanticsChange(_) + | FutureIncompatibilityReason::EditionAndFutureReleaseError(_) + | FutureIncompatibilityReason::EditionAndFutureReleaseSemanticsChange(_) + | FutureIncompatibilityReason::Custom(_) => false, + } + } } impl FutureIncompatibleInfo { diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 92ba6ceee93..971d036fa69 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -290,12 +290,7 @@ pub fn lint_level( let has_future_breakage = future_incompatible.map_or( // Default allow lints trigger too often for testing. sess.opts.unstable_opts.future_incompat_test && lint.default_level != Level::Allow, - |incompat| { - matches!( - incompat.reason, - FutureIncompatibilityReason::FutureReleaseErrorReportInDeps - ) - }, + |incompat| incompat.reason.has_future_breakage(), ); // Convert lint level to error level. -- cgit 1.4.1-3-g733a5 From def7ed08e7b27288bc861384ec166ebc5a419abc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 29 Oct 2024 17:51:38 +0000 Subject: Implement ~const Fn trait goals in the new solver --- compiler/rustc_middle/src/ty/context.rs | 6 +- .../src/solve/assembly/structural_traits.rs | 70 +++++++++++++++++ .../src/solve/effect_goals.rs | 55 ++++++++++--- .../src/solve/normalizes_to/mod.rs | 10 ++- .../src/solve/trait_goals.rs | 10 ++- compiler/rustc_type_ir/src/interner.rs | 3 +- .../const-traits/const-fns-are-early-bound.rs | 90 ---------------------- .../effects/minicore-const-fn-early-bound.rs | 22 ++++++ .../const-traits/effects/minicore-fn-fail.rs | 21 +++++ .../const-traits/effects/minicore-fn-fail.stderr | 9 +++ .../traits/const-traits/effects/minicore-works.rs | 6 ++ 11 files changed, 193 insertions(+), 109 deletions(-) delete mode 100644 tests/ui/traits/const-traits/const-fns-are-early-bound.rs create mode 100644 tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs create mode 100644 tests/ui/traits/const-traits/effects/minicore-fn-fail.rs create mode 100644 tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2ba1bf2822f..77a40762903 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -374,7 +374,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied()) } - fn is_const_impl(self, def_id: DefId) -> bool { + fn impl_is_const(self, def_id: DefId) -> bool { + self.is_conditionally_const(def_id) + } + + fn fn_is_const(self, def_id: DefId) -> bool { self.is_conditionally_const(def_id) } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 5c1a7852dc0..a56febec48c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -633,6 +633,76 @@ fn coroutine_closure_to_ambiguous_coroutine( ) } +/// This duplicates `extract_tupled_inputs_and_output_from_callable` but needs +/// to return different information (namely, the def id and args) so that we can +/// create const conditions. +/// +/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable` +/// would be wasteful. +pub(in crate::solve) fn extract_fn_def_from_const_callable( + cx: I, + self_ty: I::Ty, +) -> Result<(ty::Binder, I::DefId, I::GenericArgs), NoSolution> { + match self_ty.kind() { + ty::FnDef(def_id, args) => { + let sig = cx.fn_sig(def_id); + if sig.skip_binder().is_fn_trait_compatible() + && !cx.has_target_features(def_id) + && cx.fn_is_const(def_id) + { + Ok(( + sig.instantiate(cx, args).map_bound(|sig| (sig.inputs(), sig.output())), + def_id, + args, + )) + } else { + return Err(NoSolution); + } + } + // `FnPtr`s are not const for now. + ty::FnPtr(..) => { + return Err(NoSolution); + } + // `Closure`s are not const for now. + ty::Closure(..) => { + return Err(NoSolution); + } + // `CoroutineClosure`s are not const for now. + ty::CoroutineClosure(..) => { + return Err(NoSolution); + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::Dynamic(_, _, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Tuple(_) + | ty::Pat(_, _) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Error(_) => return Err(NoSolution), + + ty::Bound(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } +} + /// Assemble a list of predicates that would be present on a theoretical /// user impl for an object type. These predicates must be checked any time /// we assemble a built-in object candidate for an object type, since they diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0912e5effa6..282ca2fedbc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -3,15 +3,15 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::{self as ty, Interner, elaborate}; use tracing::instrument; -use super::assembly::Candidate; +use super::assembly::{Candidate, structural_traits}; use crate::delegate::SolverDelegate; -use crate::solve::assembly::{self}; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, - QueryResult, + QueryResult, assembly, }; impl assembly::GoalKind for ty::HostEffectPredicate @@ -142,7 +142,7 @@ where ty::ImplPolarity::Positive => {} }; - if !cx.is_const_impl(impl_def_id) { + if !cx.impl_is_const(impl_def_id) { return Err(NoSolution); } @@ -207,7 +207,7 @@ where _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, ) -> Result, NoSolution> { - todo!("Copy/Clone is not yet const") + Err(NoSolution) } fn consider_builtin_pointer_like_candidate( @@ -225,11 +225,48 @@ where } fn consider_builtin_fn_trait_candidates( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, _kind: rustc_type_ir::ClosureKind, ) -> Result, NoSolution> { - todo!("Fn* are not yet const") + let cx = ecx.cx(); + + let self_ty = goal.predicate.self_ty(); + let (inputs_and_output, def_id, args) = + structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| { + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) + }); + let requirements = cx + .const_conditions(def_id) + .iter_instantiated(cx, args) + .map(|trait_ref| { + ( + GoalSource::ImplWhereBound, + goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.constness)), + ) + }) + .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]); + + let pred = inputs_and_output + .map_bound(|(inputs, _)| { + ty::TraitRef::new(cx, goal.predicate.def_id(), [ + goal.predicate.self_ty(), + Ty::new_tup(cx, inputs.as_slice()), + ]) + }) + .to_host_effect_clause(cx, goal.predicate.constness); + + Self::probe_and_consider_implied_clause( + ecx, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + goal, + pred, + requirements, + ) } fn consider_builtin_async_fn_trait_candidates( @@ -314,7 +351,7 @@ where _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, ) -> Result, NoSolution> { - unreachable!("Destruct is not const") + Err(NoSolution) } fn consider_builtin_transmute_candidate( diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 129744b4db7..8a01659953d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -394,6 +394,9 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); @@ -408,8 +411,6 @@ where }) .upcast(cx); - // A built-in `Fn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -438,6 +439,9 @@ where goal_kind, env_region, )?; + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output_ty]) @@ -494,8 +498,6 @@ where ) .upcast(cx); - // A built-in `AsyncFn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 5f740590712..e64d4eed9d8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -326,6 +326,9 @@ where return ecx.forced_ambiguity(MaybeCause::Ambiguity); } }; + + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); @@ -335,8 +338,6 @@ where ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) }) .upcast(cx); - // A built-in `Fn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), @@ -364,6 +365,9 @@ where // This region doesn't matter because we're throwing away the coroutine type Region::new_static(cx), )?; + + // A built-in `AsyncFn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [ @@ -380,8 +384,6 @@ where ]) }) .upcast(cx); - // A built-in `AsyncFn` impl only holds if the output is sized. - // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f988f003c0f..6e6cf91d855 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -223,7 +223,8 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder>; - fn is_const_impl(self, def_id: Self::DefId) -> bool; + fn impl_is_const(self, def_id: Self::DefId) -> bool; + fn fn_is_const(self, def_id: Self::DefId) -> bool; fn const_conditions( self, def_id: Self::DefId, diff --git a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs b/tests/ui/traits/const-traits/const-fns-are-early-bound.rs deleted file mode 100644 index c26eaf67454..00000000000 --- a/tests/ui/traits/const-traits/const-fns-are-early-bound.rs +++ /dev/null @@ -1,90 +0,0 @@ -//@ known-bug: #110395 -//@ failure-status: 101 -//@ dont-check-compiler-stderr -// FIXME(const_trait_impl) check-pass -//@ compile-flags: -Znext-solver - -#![crate_type = "lib"] -#![allow(internal_features, incomplete_features)] -#![no_std] -#![no_core] -#![feature( - auto_traits, - const_trait_impl, - effects, - lang_items, - no_core, - staged_api, - unboxed_closures, - rustc_attrs, - marker_trait_attr, -)] -#![stable(feature = "minicore", since = "1.0.0")] - -fn test() { - fn is_const_fn(_: F) - where - F: const FnOnce<()>, - { - } - - const fn foo() {} - - is_const_fn(foo); -} - -/// ---------------------------------------------------------------------- /// -/// Const fn trait definitions - -#[const_trait] -#[lang = "fn"] -#[rustc_paren_sugar] -trait Fn: ~const FnMut { - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_mut"] -#[rustc_paren_sugar] -trait FnMut: ~const FnOnce { - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -#[const_trait] -#[lang = "fn_once"] -#[rustc_paren_sugar] -trait FnOnce { - #[lang = "fn_once_output"] - type Output; - - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -/// ---------------------------------------------------------------------- /// -/// All this other stuff needed for core. Unrelated to test. - -#[lang = "destruct"] -#[const_trait] -trait Destruct {} - -#[lang = "freeze"] -unsafe auto trait Freeze {} - -#[lang = "drop"] -#[const_trait] -trait Drop { - fn drop(&mut self); -} - -#[lang = "sized"] -trait Sized {} -#[lang = "copy"] -trait Copy {} - -#[lang = "tuple_trait"] -trait Tuple {} - -#[lang = "legacy_receiver"] -trait LegacyReceiver {} - -impl LegacyReceiver for &T {} diff --git a/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs new file mode 100644 index 00000000000..ee47f92a0bc --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-const-fn-early-bound.rs @@ -0,0 +1,22 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver -Cpanic=abort +//@ check-pass + +#![feature(no_core, const_trait_impl)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn is_const_fn(_: F) +where + F: const FnOnce(), +{ +} + +const fn foo() {} + +fn test() { + is_const_fn(foo); +} diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs new file mode 100644 index 00000000000..ae1cbc6ca58 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.rs @@ -0,0 +1,21 @@ +//@ aux-build:minicore.rs +//@ compile-flags: --crate-type=lib -Znext-solver + +#![feature(no_core, const_trait_impl)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +const fn call_indirect(t: &T) { t() } + +#[const_trait] +trait Foo {} +impl Foo for () {} +const fn foo() {} + +const fn test() { + call_indirect(&foo::<()>); + //~^ ERROR the trait bound `(): ~const Foo` is not satisfied +} diff --git a/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr new file mode 100644 index 00000000000..cf158643b34 --- /dev/null +++ b/tests/ui/traits/const-traits/effects/minicore-fn-fail.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): ~const Foo` is not satisfied + --> $DIR/minicore-fn-fail.rs:19:5 + | +LL | call_indirect(&foo::<()>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/effects/minicore-works.rs b/tests/ui/traits/const-traits/effects/minicore-works.rs index bfbfa8b2d05..c79b4fc07df 100644 --- a/tests/ui/traits/const-traits/effects/minicore-works.rs +++ b/tests/ui/traits/const-traits/effects/minicore-works.rs @@ -20,3 +20,9 @@ const fn test_op() { let _x = Add::add(1, 2); let _y = Custom + Custom; } + +const fn call_indirect(t: &T) { t() } + +const fn call() { + call_indirect(&call); +} -- cgit 1.4.1-3-g733a5 From 57ed8e8436eddcaacb4bce97de23a2d23ff8affe Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Wed, 20 Nov 2024 10:47:28 +0100 Subject: Fix LLVM target triple for `x86_64-win7-windows-msvc` The vendor field needs to be `pc` rather than `win7`. --- compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs index 3a3716db350..f42188ec61a 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs @@ -8,7 +8,7 @@ pub(crate) fn target() -> Target { base.vendor = "win7".into(); Target { - llvm_target: "x86_64-win7-windows-msvc".into(), + llvm_target: "x86_64-pc-windows-msvc".into(), metadata: crate::spec::TargetMetadata { description: Some("64-bit Windows 7 support".into()), tier: Some(3), -- cgit 1.4.1-3-g733a5 From d04088fa366f5a764ba3b5055450db083b4406b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Nov 2024 11:05:53 +0100 Subject: interpret: make typing_env field private --- compiler/rustc_const_eval/src/const_eval/eval_queries.rs | 5 ++--- compiler/rustc_const_eval/src/const_eval/machine.rs | 4 ++-- compiler/rustc_const_eval/src/interpret/eval_context.rs | 4 ++-- compiler/rustc_mir_transform/src/gvn.rs | 4 ++-- src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs | 7 ++++--- src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs | 11 ++++++----- src/tools/miri/src/machine.rs | 9 +++++---- 7 files changed, 23 insertions(+), 21 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 64331eea75c..647d880e2bf 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -7,7 +7,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; @@ -30,7 +30,6 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( cid: GlobalId<'tcx>, body: &'tcx mir::Body<'tcx>, ) -> InterpResult<'tcx, R> { - trace!(?ecx.typing_env); let tcx = *ecx.tcx; assert!( cid.promoted.is_some() @@ -220,7 +219,7 @@ pub(super) fn op_to_const<'tcx>( let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( - ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env).kind(), + ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(), ty::Str | ty::Slice(..), ), "`ConstValue::Slice` is for slice-tailed types only, but got {}", diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index db82050c73c..b27e3606f38 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Span; @@ -667,7 +667,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { .is_some_and(|p| !p.immutable()) { // That next check is expensive, that's why we have all the guards above. - let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env); + let is_immutable = ty.is_freeze(*ecx.tcx, ecx.typing_env()); let place = ecx.ref_to_mplace(val)?; let new_place = if is_immutable { place.map_provenance(CtfeProvenance::as_immutable) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 42fdf32e91e..fe93a48c2f2 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -39,8 +39,8 @@ pub struct InterpCx<'tcx, M: Machine<'tcx>> { pub tcx: TyCtxtAt<'tcx>, /// The current context in case we're evaluating in a - /// polymorphic context. This always uses `ty::TypingMode::PostAnalysis` - pub typing_env: ty::TypingEnv<'tcx>, + /// polymorphic context. This always uses `ty::TypingMode::PostAnalysis`. + pub(super) typing_env: ty::TypingEnv<'tcx>, /// The virtual memory system. pub memory: Memory<'tcx, M>, diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b3d9af37204..976f4a8e919 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -100,7 +100,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; @@ -294,7 +294,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } fn typing_env(&self) -> ty::TypingEnv<'tcx> { - self.ecx.typing_env + self.ecx.typing_env() } #[instrument(level = "trace", skip(self), ret)] diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 9627447b342..a855603eeb3 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -12,6 +12,7 @@ use std::{cmp, mem}; use rustc_abi::{BackendRepr, Size}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Mutability, RetagKind}; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty}; use self::diagnostics::{RetagCause, RetagInfo}; @@ -70,7 +71,7 @@ impl NewPermission { access: None, protector: None, } - } else if pointee.is_unpin(*cx.tcx, cx.typing_env) { + } else if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular full mutable reference. On `FnEntry` this is `noalias` and `dereferenceable`. NewPermission::Uniform { perm: Permission::Unique, @@ -128,7 +129,7 @@ impl NewPermission { fn from_box_ty<'tcx>(ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). let pointee = ty.builtin_deref(true).unwrap(); - if pointee.is_unpin(*cx.tcx, cx.typing_env) { + if pointee.is_unpin(*cx.tcx, cx.typing_env()) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). NewPermission::Uniform { @@ -607,7 +608,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { match new_perm { NewPermission::Uniform { perm, .. } => write!(kind_str, "{perm:?} permission").unwrap(), - NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env) => + NewPermission::FreezeSensitive { freeze_perm, .. } if ty.is_freeze(*this.tcx, this.typing_env()) => write!(kind_str, "{freeze_perm:?} permission").unwrap(), NewPermission::FreezeSensitive { freeze_perm, nonfreeze_perm, .. } => write!(kind_str, "{freeze_perm:?}/{nonfreeze_perm:?} permission for frozen/non-frozen parts").unwrap(), diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 61a2e2bc8d9..8469744bbc4 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -1,5 +1,6 @@ use rustc_abi::{BackendRepr, Size}; use rustc_middle::mir::{Mutability, RetagKind}; +use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefId; @@ -131,8 +132,8 @@ impl<'tcx> NewPermission { kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>, ) -> Option { - let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env); - let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env); + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); + let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env()); let is_protected = kind == RetagKind::FnEntry; // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`, // interior mutability and protectors interact poorly. @@ -163,10 +164,10 @@ impl<'tcx> NewPermission { zero_size: bool, ) -> Option { let pointee = ty.builtin_deref(true).unwrap(); - pointee.is_unpin(*cx.tcx, cx.typing_env).then_some(()).map(|()| { + pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. - let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env); + let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env()); let protected = kind == RetagKind::FnEntry; let initial_state = Permission::new_reserved(ty_is_freeze, protected); Self { @@ -520,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Note: if we were to inline `new_reserved` below we would find out that // `ty_is_freeze` is eventually unused because it appears in a `ty_is_freeze || true`. // We are nevertheless including it here for clarity. - let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env); + let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); // Retag it. With protection! That is the entire point. let new_perm = NewPermission { initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true), diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 3ab606e5847..7b03aed4763 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -17,7 +17,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::static_assert_size; use rustc_middle::mir; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{ + HasTyCtxt, HasTypingEnv, LayoutCx, LayoutError, LayoutOf, TyAndLayout, +}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::config::InliningThreshold; use rustc_span::def_id::{CrateNum, DefId}; @@ -1127,9 +1129,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { }; let info = ecx.get_alloc_info(alloc_id); let def_ty = ecx.tcx.type_of(def_id).instantiate_identity(); - let extern_decl_layout = ecx.tcx.layout_of( - ecx.typing_env.as_query_input(def_ty) - ).unwrap(); + let extern_decl_layout = + ecx.tcx.layout_of(ecx.typing_env().as_query_input(def_ty)).unwrap(); if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align { throw_unsup_format!( "extern static `{link_name}` has been declared as `{krate}::{name}` \ -- cgit 1.4.1-3-g733a5 From 297b618944d4619a1990b1992d9142c6cf893dc6 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Mon, 2 Sep 2024 01:13:07 +0800 Subject: reduce false positives of tail-expr-drop-order from consumed values take 2 open up coroutines tweak the wordings the lint works up until 2021 We were missing one case, for ADTs, which was causing `Result` to yield incorrect results. only include field spans with significant types deduplicate and eliminate field spans switch to emit spans to impl Drops Co-authored-by: Niko Matsakis collect drops instead of taking liveness diff apply some suggestions and add explantory notes small fix on the cache let the query recurse through coroutine new suggestion format with extracted variable name fine-tune the drop span and messages bugfix on runtime borrows tweak message wording filter out ecosystem types earlier apply suggestions clippy check lint level at session level further restrict applicability of the lint translate bid into nop for stable mir detect cycle in type structure --- compiler/rustc_borrowck/src/dataflow.rs | 1 + compiler/rustc_borrowck/src/lib.rs | 2 + .../src/polonius/loan_invalidations.rs | 1 + compiler/rustc_borrowck/src/type_check/mod.rs | 1 + compiler/rustc_codegen_cranelift/src/base.rs | 1 + compiler/rustc_codegen_cranelift/src/constant.rs | 1 + compiler/rustc_codegen_ssa/src/mir/statement.rs | 1 + .../rustc_const_eval/src/check_consts/check.rs | 1 + compiler/rustc_const_eval/src/interpret/step.rs | 3 + compiler/rustc_hir_analysis/src/check/region.rs | 20 +- compiler/rustc_index/src/bit_set.rs | 140 +++- compiler/rustc_lint/messages.ftl | 3 - compiler/rustc_lint/src/lib.rs | 3 - compiler/rustc_lint/src/tail_expr_drop_order.rs | 308 --------- compiler/rustc_lint_defs/src/builtin.rs | 78 +++ compiler/rustc_middle/src/middle/region.rs | 5 + compiler/rustc_middle/src/mir/pretty.rs | 5 + compiler/rustc_middle/src/mir/syntax.rs | 28 + compiler/rustc_middle/src/mir/visit.rs | 1 + compiler/rustc_middle/src/query/keys.rs | 8 + compiler/rustc_middle/src/query/mod.rs | 22 + compiler/rustc_middle/src/thir.rs | 17 +- compiler/rustc_middle/src/ty/rvalue_scopes.rs | 27 +- .../rustc_mir_build/src/build/expr/as_operand.rs | 23 +- .../rustc_mir_build/src/build/expr/as_place.rs | 3 +- .../rustc_mir_build/src/build/expr/as_rvalue.rs | 14 +- compiler/rustc_mir_build/src/build/expr/as_temp.rs | 21 +- compiler/rustc_mir_build/src/build/expr/into.rs | 18 +- compiler/rustc_mir_build/src/build/expr/stmt.rs | 13 +- compiler/rustc_mir_build/src/build/matches/mod.rs | 13 +- compiler/rustc_mir_build/src/build/scope.rs | 93 ++- compiler/rustc_mir_build/src/thir/cx/expr.rs | 69 +- compiler/rustc_mir_dataflow/src/impls/liveness.rs | 1 + .../src/impls/storage_liveness.rs | 1 + .../rustc_mir_dataflow/src/move_paths/builder.rs | 1 + compiler/rustc_mir_transform/messages.ftl | 25 + compiler/rustc_mir_transform/src/coroutine.rs | 1 + .../src/coverage/spans/from_mir.rs | 1 + .../rustc_mir_transform/src/dataflow_const_prop.rs | 3 +- .../src/dead_store_elimination.rs | 3 +- compiler/rustc_mir_transform/src/dest_prop.rs | 5 +- compiler/rustc_mir_transform/src/jump_threading.rs | 1 + compiler/rustc_mir_transform/src/lib.rs | 2 + .../src/lint_tail_expr_drop_order.rs | 701 +++++++++++++++++++++ .../src/remove_noop_landing_pads.rs | 1 + compiler/rustc_mir_transform/src/remove_zsts.rs | 1 + compiler/rustc_mir_transform/src/simplify.rs | 18 +- compiler/rustc_mir_transform/src/validate.rs | 2 + compiler/rustc_smir/src/rustc_smir/convert/mir.rs | 4 + compiler/rustc_ty_utils/src/needs_drop.rs | 68 +- .../clippy_utils/src/qualify_min_const_fn.rs | 1 + tests/ui/drop/lint-tail-expr-drop-order-gated.rs | 7 +- tests/ui/drop/lint-tail-expr-drop-order.rs | 215 ++++++- tests/ui/drop/lint-tail-expr-drop-order.stderr | 327 +++++++++- tests/ui/thir-print/thir-flat-const-variant.stdout | 162 +++-- tests/ui/thir-print/thir-flat.stdout | 18 +- tests/ui/thir-print/thir-tree-match.stdout | 28 +- tests/ui/thir-print/thir-tree.stdout | 4 +- 58 files changed, 2011 insertions(+), 534 deletions(-) delete mode 100644 compiler/rustc_lint/src/tail_expr_drop_order.rs create mode 100644 compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 7adc7a8863e..452038bc328 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -641,6 +641,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::Coverage(..) | mir::StatementKind::Intrinsic(..) | mir::StatementKind::ConstEvalCounter + | mir::StatementKind::BackwardIncompatibleDropHint { .. } | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 03f7b05d1e3..16a4f699177 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -652,6 +652,8 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< | StatementKind::Coverage(..) // These do not actually affect borrowck | StatementKind::ConstEvalCounter + // This do not affect borrowck + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index d1b65943199..f646beeecf7 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -88,6 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { | StatementKind::Nop | StatementKind::Retag { .. } | StatementKind::Deinit(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index c6b34d5bf1d..3a7ed711f68 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1252,6 +1252,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 77ee9773940..70b7d92ce15 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -924,6 +924,7 @@ fn codegen_stmt<'tcx>( | StatementKind::FakeRead(..) | StatementKind::Retag { .. } | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => unreachable!(), diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 5311547309c..abe6085b04f 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -583,6 +583,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 1681ea1de5f..cd55a838a75 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -92,6 +92,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::ConstEvalCounter | mir::StatementKind::PlaceMention(..) + | mir::StatementKind::BackwardIncompatibleDropHint { .. } | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 8e96d365beb..1129b5caec5 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -609,6 +609,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 98aca37e73e..b61865be667 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -143,6 +143,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Defined to do nothing. These are added by optimization passes, to avoid changing the // size of MIR constantly. Nop => {} + + // Only used for temporary lifetime lints + BackwardIncompatibleDropHint { .. } => {} } interp_ok(()) diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 679f6ccb816..b9cb48cafdc 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -17,6 +17,7 @@ use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::middle::region::*; use rustc_middle::ty::TyCtxt; +use rustc_session::lint; use rustc_span::source_map; use tracing::debug; @@ -167,8 +168,23 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } } if let Some(tail_expr) = blk.expr { - if blk.span.edition().at_least_rust_2024() { - visitor.terminating_scopes.insert(tail_expr.hir_id.local_id); + let local_id = tail_expr.hir_id.local_id; + let edition = blk.span.edition(); + if edition.at_least_rust_2024() { + visitor.terminating_scopes.insert(local_id); + } else if !visitor + .tcx + .lints_that_dont_need_to_run(()) + .contains(&lint::LintId::of(lint::builtin::TAIL_EXPR_DROP_ORDER)) + { + // If this temporary scope will be changing once the codebase adopts Rust 2024, + // and we are linting about possible semantic changes that would result, + // then record this node-id in the field `backwards_incompatible_scope` + // for future reference. + visitor + .scope_tree + .backwards_incompatible_scope + .insert(local_id, Scope { id: local_id, data: ScopeData::Node }); } visitor.visit_expr(tail_expr); } diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index c2b9cae680b..a9239489222 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -460,6 +460,10 @@ impl ChunkedBitSet { self.chunks.iter().map(|chunk| chunk.count()).sum() } + pub fn is_empty(&self) -> bool { + self.chunks.iter().all(|chunk| matches!(chunk, Chunk::Zeros(..) | Chunk::Ones(0))) + } + /// Returns `true` if `self` contains `elem`. #[inline] pub fn contains(&self, elem: T) -> bool { @@ -668,12 +672,140 @@ impl BitRelations> for ChunkedBitSet { changed } - fn subtract(&mut self, _other: &ChunkedBitSet) -> bool { - unimplemented!("implement if/when necessary"); + fn subtract(&mut self, other: &ChunkedBitSet) -> bool { + assert_eq!(self.domain_size, other.domain_size); + debug_assert_eq!(self.chunks.len(), other.chunks.len()); + + let mut changed = false; + for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) { + match (&mut self_chunk, &other_chunk) { + (Zeros(..), _) | (_, Zeros(..)) => {} + ( + Ones(self_chunk_domain_size) | Mixed(self_chunk_domain_size, _, _), + Ones(other_chunk_domain_size), + ) => { + debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + changed = true; + *self_chunk = Zeros(*self_chunk_domain_size); + } + ( + Ones(self_chunk_domain_size), + Mixed(other_chunk_domain_size, other_chunk_count, other_chunk_words), + ) => { + debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + changed = true; + let num_words = num_words(*self_chunk_domain_size as usize); + debug_assert!(num_words > 0 && num_words <= CHUNK_WORDS); + let mut tail_mask = + 1 << (*other_chunk_domain_size - ((num_words - 1) * WORD_BITS) as u16) - 1; + let mut self_chunk_words = **other_chunk_words; + for word in self_chunk_words[0..num_words].iter_mut().rev() { + *word = !*word & tail_mask; + tail_mask = u64::MAX; + } + let self_chunk_count = *self_chunk_domain_size - *other_chunk_count; + debug_assert_eq!( + self_chunk_count, + self_chunk_words[0..num_words] + .iter() + .map(|w| w.count_ones() as ChunkSize) + .sum() + ); + *self_chunk = + Mixed(*self_chunk_domain_size, self_chunk_count, Rc::new(self_chunk_words)); + } + ( + Mixed( + self_chunk_domain_size, + ref mut self_chunk_count, + ref mut self_chunk_words, + ), + Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), + ) => { + // See [`>>::union`] for the explanation + let op = |a: u64, b: u64| a & !b; + let num_words = num_words(*self_chunk_domain_size as usize); + if bitwise_changes( + &self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ) { + let self_chunk_words = Rc::make_mut(self_chunk_words); + let has_changed = bitwise( + &mut self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ); + debug_assert!(has_changed); + *self_chunk_count = self_chunk_words[0..num_words] + .iter() + .map(|w| w.count_ones() as ChunkSize) + .sum(); + if *self_chunk_count == 0 { + *self_chunk = Zeros(*self_chunk_domain_size); + } + changed = true; + } + } + } + } + changed } - fn intersect(&mut self, _other: &ChunkedBitSet) -> bool { - unimplemented!("implement if/when necessary"); + fn intersect(&mut self, other: &ChunkedBitSet) -> bool { + assert_eq!(self.domain_size, other.domain_size); + debug_assert_eq!(self.chunks.len(), other.chunks.len()); + + let mut changed = false; + for (mut self_chunk, other_chunk) in self.chunks.iter_mut().zip(other.chunks.iter()) { + match (&mut self_chunk, &other_chunk) { + (Zeros(..), _) | (_, Ones(..)) => {} + ( + Ones(self_chunk_domain_size), + Zeros(other_chunk_domain_size) | Mixed(other_chunk_domain_size, ..), + ) + | (Mixed(self_chunk_domain_size, ..), Zeros(other_chunk_domain_size)) => { + debug_assert_eq!(self_chunk_domain_size, other_chunk_domain_size); + changed = true; + *self_chunk = other_chunk.clone(); + } + ( + Mixed( + self_chunk_domain_size, + ref mut self_chunk_count, + ref mut self_chunk_words, + ), + Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), + ) => { + // See [`>>::union`] for the explanation + let op = |a, b| a & b; + let num_words = num_words(*self_chunk_domain_size as usize); + if bitwise_changes( + &self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ) { + let self_chunk_words = Rc::make_mut(self_chunk_words); + let has_changed = bitwise( + &mut self_chunk_words[0..num_words], + &other_chunk_words[0..num_words], + op, + ); + debug_assert!(has_changed); + *self_chunk_count = self_chunk_words[0..num_words] + .iter() + .map(|w| w.count_ones() as ChunkSize) + .sum(); + if *self_chunk_count == 0 { + *self_chunk = Zeros(*self_chunk_domain_size); + } + changed = true; + } + } + } + } + + changed } } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 6e35d89b488..69fd7f2d8b2 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -772,9 +772,6 @@ lint_suspicious_double_ref_clone = lint_suspicious_double_ref_deref = using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type -lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - .label = these values have significant drop implementation and will observe changes in drop order under Edition 2024 - lint_trailing_semi_macro = trailing semicolon in macro used in expression position .note1 = macro invocations at the end of a block are treated as expressions .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 86112277504..4cf5c7b4ff9 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -75,7 +75,6 @@ mod redundant_semicolon; mod reference_casting; mod shadowed_into_iter; mod static_mut_refs; -mod tail_expr_drop_order; mod traits; mod types; mod unit_bindings; @@ -116,7 +115,6 @@ use rustc_middle::ty::TyCtxt; use shadowed_into_iter::ShadowedIntoIter; pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use static_mut_refs::*; -use tail_expr_drop_order::TailExprDropOrder; use traits::*; use types::*; use unit_bindings::*; @@ -240,7 +238,6 @@ late_lint_methods!( AsyncFnInTrait: AsyncFnInTrait, NonLocalDefinitions: NonLocalDefinitions::default(), ImplTraitOvercaptures: ImplTraitOvercaptures, - TailExprDropOrder: TailExprDropOrder, IfLetRescope: IfLetRescope::default(), StaticMutRefs: StaticMutRefs, UnqualifiedLocalImports: UnqualifiedLocalImports, diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs deleted file mode 100644 index 19763ce1ec5..00000000000 --- a/compiler/rustc_lint/src/tail_expr_drop_order.rs +++ /dev/null @@ -1,308 +0,0 @@ -use std::mem::swap; - -use rustc_ast::UnOp; -use rustc_hir::def::Res; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Block, Expr, ExprKind, LetStmt, Pat, PatKind, QPath, StmtKind}; -use rustc_macros::LintDiagnostic; -use rustc_middle::ty; -use rustc_session::lint::FutureIncompatibilityReason; -use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::Span; -use rustc_span::edition::Edition; - -use crate::{LateContext, LateLintPass}; - -declare_lint! { - /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, - /// that runs a custom `Drop` destructor. - /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior. - /// This lint detects those cases and provides you information on those values and their custom destructor implementations. - /// Your discretion on this information is required. - /// - /// ### Example - /// ```rust,edition2021 - /// #![warn(tail_expr_drop_order)] - /// struct Droppy(i32); - /// impl Droppy { - /// fn get(&self) -> i32 { - /// self.0 - /// } - /// } - /// impl Drop for Droppy { - /// fn drop(&mut self) { - /// // This is a custom destructor and it induces side-effects that is observable - /// // especially when the drop order at a tail expression changes. - /// println!("loud drop {}", self.0); - /// } - /// } - /// fn edition_2021() -> i32 { - /// let another_droppy = Droppy(0); - /// Droppy(1).get() - /// } - /// fn main() { - /// edition_2021(); - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// In tail expression of blocks or function bodies, - /// values of type with significant `Drop` implementation has an ill-specified drop order - /// before Edition 2024 so that they are dropped only after dropping local variables. - /// Edition 2024 introduces a new rule with drop orders for them, - /// so that they are dropped first before dropping local variables. - /// - /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary - /// implementation of the `Drop` trait on the type, with exceptions including `Vec`, - /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise - /// so long that the generic types have no significant destructor recursively. - /// In other words, a type has a significant drop destructor when it has a `Drop` implementation - /// or its destructor invokes a significant destructor on a type. - /// Since we cannot completely reason about the change by just inspecting the existence of - /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. - /// - /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy` - /// does in Edition 2024. - /// No fix will be proposed by this lint. - /// However, the most probable fix is to hoist `Droppy` into its own local variable binding. - /// ```rust - /// struct Droppy(i32); - /// impl Droppy { - /// fn get(&self) -> i32 { - /// self.0 - /// } - /// } - /// fn edition_2024() -> i32 { - /// let value = Droppy(0); - /// let another_droppy = Droppy(1); - /// value.get() - /// } - /// ``` - pub TAIL_EXPR_DROP_ORDER, - Allow, - "Detect and warn on significant change in drop order in tail expression location", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "issue #123739 ", - }; -} - -declare_lint_pass!(TailExprDropOrder => [TAIL_EXPR_DROP_ORDER]); - -impl TailExprDropOrder { - fn check_fn_or_closure<'tcx>( - cx: &LateContext<'tcx>, - fn_kind: hir::intravisit::FnKind<'tcx>, - body: &'tcx hir::Body<'tcx>, - def_id: rustc_span::def_id::LocalDefId, - ) { - let mut locals = vec![]; - if matches!(fn_kind, hir::intravisit::FnKind::Closure) { - for &capture in cx.tcx.closure_captures(def_id) { - if matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue) - && capture.place.ty().has_significant_drop(cx.tcx, cx.typing_env()) - { - locals.push(capture.var_ident.span); - } - } - } - for param in body.params { - if cx - .typeck_results() - .node_type(param.hir_id) - .has_significant_drop(cx.tcx, cx.typing_env()) - { - locals.push(param.span); - } - } - if let hir::ExprKind::Block(block, _) = body.value.kind { - LintVisitor { cx, locals }.check_block_inner(block); - } else { - LintTailExpr { cx, locals: &locals, is_root_tail_expr: true }.visit_expr(body.value); - } - } -} - -impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - fn_kind: hir::intravisit::FnKind<'tcx>, - _: &'tcx hir::FnDecl<'tcx>, - body: &'tcx hir::Body<'tcx>, - _: Span, - def_id: rustc_span::def_id::LocalDefId, - ) { - if !body.value.span.edition().at_least_rust_2024() { - Self::check_fn_or_closure(cx, fn_kind, body, def_id); - } - } -} - -struct LintVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - // We only record locals that have significant drops - locals: Vec, -} - -struct LocalCollector<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - locals: &'a mut Vec, -} - -impl<'a, 'tcx> Visitor<'tcx> for LocalCollector<'a, 'tcx> { - type Result = (); - fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { - if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind { - let ty = self.cx.typeck_results().node_type(id); - if ty.has_significant_drop(self.cx.tcx, self.cx.typing_env()) { - self.locals.push(ident.span); - } - if let Some(pat) = pat { - self.visit_pat(pat); - } - } else { - intravisit::walk_pat(self, pat); - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> { - fn visit_block(&mut self, block: &'tcx Block<'tcx>) { - let mut locals = <_>::default(); - swap(&mut locals, &mut self.locals); - self.check_block_inner(block); - swap(&mut locals, &mut self.locals); - } - fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { - LocalCollector { cx: self.cx, locals: &mut self.locals }.visit_local(local); - } -} - -impl<'a, 'tcx> LintVisitor<'a, 'tcx> { - fn check_block_inner(&mut self, block: &Block<'tcx>) { - if block.span.at_least_rust_2024() { - // We only lint up to Edition 2021 - return; - } - let Some(tail_expr) = block.expr else { return }; - for stmt in block.stmts { - match stmt.kind { - StmtKind::Let(let_stmt) => self.visit_local(let_stmt), - StmtKind::Item(_) => {} - StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), - } - } - if self.locals.is_empty() { - return; - } - LintTailExpr { cx: self.cx, locals: &self.locals, is_root_tail_expr: true } - .visit_expr(tail_expr); - } -} - -struct LintTailExpr<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - is_root_tail_expr: bool, - locals: &'a [Span], -} - -impl<'a, 'tcx> LintTailExpr<'a, 'tcx> { - fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool { - loop { - match expr.kind { - ExprKind::Index(access, _, _) | ExprKind::Field(access, _) => expr = access, - ExprKind::AddrOf(_, _, referee) | ExprKind::Unary(UnOp::Deref, referee) => { - expr = referee - } - ExprKind::Path(_) - if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind - && let [local, ..] = path.segments - && let Res::Local(_) = local.res => - { - return true; - } - _ => return false, - } - } - } - - fn expr_generates_nonlocal_droppy_value(&self, expr: &Expr<'tcx>) -> bool { - if Self::expr_eventually_point_into_local(expr) { - return false; - } - self.cx - .typeck_results() - .expr_ty(expr) - .has_significant_drop(self.cx.tcx, self.cx.typing_env()) - } -} - -impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if self.is_root_tail_expr { - self.is_root_tail_expr = false; - } else if self.expr_generates_nonlocal_droppy_value(expr) { - self.cx.tcx.emit_node_span_lint( - TAIL_EXPR_DROP_ORDER, - expr.hir_id, - expr.span, - TailExprDropOrderLint { spans: self.locals.to_vec() }, - ); - return; - } - match expr.kind { - ExprKind::Match(scrutinee, _, _) => self.visit_expr(scrutinee), - - ExprKind::ConstBlock(_) - | ExprKind::Array(_) - | ExprKind::Break(_, _) - | ExprKind::Continue(_) - | ExprKind::Ret(_) - | ExprKind::Become(_) - | ExprKind::Yield(_, _) - | ExprKind::InlineAsm(_) - | ExprKind::If(_, _, _) - | ExprKind::Loop(_, _, _, _) - | ExprKind::Closure(_) - | ExprKind::DropTemps(_) - | ExprKind::OffsetOf(_, _) - | ExprKind::Assign(_, _, _) - | ExprKind::AssignOp(_, _, _) - | ExprKind::Lit(_) - | ExprKind::Err(_) => {} - - ExprKind::MethodCall(_, _, _, _) - | ExprKind::Call(_, _) - | ExprKind::Type(_, _) - | ExprKind::Tup(_) - | ExprKind::Binary(_, _, _) - | ExprKind::Unary(_, _) - | ExprKind::Path(_) - | ExprKind::Let(_) - | ExprKind::Cast(_, _) - | ExprKind::Field(_, _) - | ExprKind::Index(_, _, _) - | ExprKind::AddrOf(_, _, _) - | ExprKind::Struct(_, _, _) - | ExprKind::Repeat(_, _) => intravisit::walk_expr(self, expr), - - ExprKind::Block(_, _) => { - // We do not lint further because the drop order stays the same inside the block - } - } - } - fn visit_block(&mut self, block: &'tcx Block<'tcx>) { - LintVisitor { cx: self.cx, locals: <_>::default() }.check_block_inner(block); - } -} - -#[derive(LintDiagnostic)] -#[diag(lint_tail_expr_drop_order)] -struct TailExprDropOrderLint { - #[label] - pub spans: Vec, -} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 313a7badf19..9036741e078 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -101,6 +101,7 @@ declare_lint_pass! { SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, STABLE_FEATURES, + TAIL_EXPR_DROP_ORDER, TEST_UNSTABLE_LINT, TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TRIVIAL_CASTS, @@ -4994,6 +4995,83 @@ declare_lint! { "detects pointer to integer transmutes in const functions and associated constants", } +declare_lint! { + /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, + /// that runs a custom `Drop` destructor. + /// Some of them may be dropped earlier in Edition 2024 that they used to in Edition 2021 and prior. + /// This lint detects those cases and provides you information on those values and their custom destructor implementations. + /// Your discretion on this information is required. + /// + /// ### Example + /// ```rust,edition2021 + /// #![warn(tail_expr_drop_order)] + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// impl Drop for Droppy { + /// fn drop(&mut self) { + /// // This is a custom destructor and it induces side-effects that is observable + /// // especially when the drop order at a tail expression changes. + /// println!("loud drop {}", self.0); + /// } + /// } + /// fn edition_2021() -> i32 { + /// let another_droppy = Droppy(0); + /// Droppy(1).get() + /// } + /// fn main() { + /// edition_2021(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In tail expression of blocks or function bodies, + /// values of type with significant `Drop` implementation has an ill-specified drop order + /// before Edition 2024 so that they are dropped only after dropping local variables. + /// Edition 2024 introduces a new rule with drop orders for them, + /// so that they are dropped first before dropping local variables. + /// + /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary + /// implementation of the `Drop` trait on the type, with exceptions including `Vec`, + /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise + /// so long that the generic types have no significant destructor recursively. + /// In other words, a type has a significant drop destructor when it has a `Drop` implementation + /// or its destructor invokes a significant destructor on a type. + /// Since we cannot completely reason about the change by just inspecting the existence of + /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. + /// + /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy` + /// does in Edition 2024. + /// No fix will be proposed by this lint. + /// However, the most probable fix is to hoist `Droppy` into its own local variable binding. + /// ```rust + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// fn edition_2024() -> i32 { + /// let value = Droppy(0); + /// let another_droppy = Droppy(1); + /// value.get() + /// } + /// ``` + pub TAIL_EXPR_DROP_ORDER, + Allow, + "Detect and warn on significant change in drop order in tail expression location", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "issue #123739 ", + }; +} + declare_lint! { /// The `rust_2024_guarded_string_incompatible_syntax` lint detects `#` tokens /// that will be parsed as part of a guarded string literal in Rust 2024. diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 4e44de33611..114211b27c1 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -236,6 +236,11 @@ pub struct ScopeTree { /// during type check based on a traversal of the AST. pub rvalue_candidates: HirIdMap, + /// Backwards incompatible scoping that will be introduced in future editions. + /// This information is used later for linting to identify locals and + /// temporary values that will receive backwards-incompatible drop orders. + pub backwards_incompatible_scope: UnordMap, + /// If there are any `yield` nested within a scope, this map /// stores the `Span` of the last one and its index in the /// postorder of the Visitor traversal on the HIR. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f0e2b7a376c..2bfcd0a6227 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -834,6 +834,11 @@ impl Debug for Statement<'_> { Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"), ConstEvalCounter => write!(fmt, "ConstEvalCounter"), Nop => write!(fmt, "nop"), + BackwardIncompatibleDropHint { ref place, reason: _ } => { + // For now, we don't record the reason because there is only one use case, + // which is to report breaking change in drop order by Edition 2024 + write!(fmt, "backward incompatible drop({place:?})") + } } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 2083279e128..fea940ea47c 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -432,6 +432,18 @@ pub enum StatementKind<'tcx> { /// No-op. Useful for deleting instructions without affecting statement indices. Nop, + + /// Marker statement indicating where `place` would be dropped. + /// This is semantically equivalent to `Nop`, so codegen and MIRI should interpret this + /// statement as such. + /// The only use case of this statement is for linting in MIR to detect temporary lifetime + /// changes. + BackwardIncompatibleDropHint { + /// Place to drop + place: Box>, + /// Reason for backward incompatibility + reason: BackwardIncompatibleDropReason, + }, } impl StatementKind<'_> { @@ -452,6 +464,7 @@ impl StatementKind<'_> { StatementKind::Intrinsic(..) => "Intrinsic", StatementKind::ConstEvalCounter => "ConstEvalCounter", StatementKind::Nop => "Nop", + StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", } } } @@ -897,6 +910,21 @@ pub enum TerminatorKind<'tcx> { }, } +#[derive( + Clone, + Debug, + TyEncodable, + TyDecodable, + Hash, + HashStable, + PartialEq, + TypeFoldable, + TypeVisitable +)] +pub enum BackwardIncompatibleDropReason { + Edition2024, +} + impl TerminatorKind<'_> { /// Returns a simple string representation of a `TerminatorKind` variant, independent of any /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 9f9ee8497b6..62c340d99e3 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -452,6 +452,7 @@ macro_rules! make_mir_visitor { } StatementKind::ConstEvalCounter => {} StatementKind::Nop => {} + StatementKind::BackwardIncompatibleDropHint { .. } => {} } } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 8fd99303622..970dc72e1ff 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -360,6 +360,14 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) { } } +impl<'tcx> Key for ty::ParamEnvAnd<'tcx, Ty<'tcx>> { + type Cache = DefaultCache; + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for ty::TraitRef<'tcx> { type Cache = DefaultCache; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9ae519dfe7e..3fdb38a433e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1448,6 +1448,28 @@ rustc_queries! { cache_on_disk_if { false } } + /// Returns a list of types which (a) have a potentially significant destructor + /// and (b) may be dropped as a result of dropping a value of some type `ty` + /// (in the given environment). + /// + /// The idea of "significant" drop is somewhat informal and is used only for + /// diagnostics and edition migrations. The idea is that a significant drop may have + /// some visible side-effect on execution; freeing memory is NOT considered a side-effect. + /// The rules are as follows: + /// * Type with no explicit drop impl do not have significant drop. + /// * Types with a drop impl are assumed to have significant drop unless they have a `#[rustc_insignificant_dtor]` annotation. + /// + /// Note that insignificant drop is a "shallow" property. A type like `Vec` does not + /// have significant drop but the type `LockGuard` does, and so if `ty = Vec` + /// then the return value would be `&[LockGuard]`. + /// *IMPORTANT*: *DO NOT* run this query before promoted MIR body is constructed, + /// because this query partially depends on that query. + /// Otherwise, there is a risk of query cycles. + query list_significant_drop_tys(ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx ty::List> { + desc { |tcx| "computing when `{}` has a significant destructor", ty.value } + cache_on_disk_if { false } + } + /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode, and will normalize the input type. query layout_of( diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 8f26e05cb72..06336d57704 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -247,13 +247,24 @@ pub struct Expr<'tcx> { pub ty: Ty<'tcx>, /// The lifetime of this expression if it should be spilled into a - /// temporary; should be `None` only if in a constant context - pub temp_lifetime: Option, + /// temporary + pub temp_lifetime: TempLifetime, /// span of the expression in the source pub span: Span, } +/// Temporary lifetime information for THIR expressions +#[derive(Clone, Copy, Debug, HashStable)] +pub struct TempLifetime { + /// Lifetime for temporaries as expected. + /// This should be `None` in a constant context. + pub temp_lifetime: Option, + /// If `Some(lt)`, indicates that the lifetime of this temporary will change to `lt` in a future edition. + /// If `None`, then no changes are expected, or lints are disabled. + pub backwards_incompatible: Option, +} + #[derive(Clone, Debug, HashStable)] pub enum ExprKind<'tcx> { /// `Scope`s are used to explicitly mark destruction scopes, @@ -1087,7 +1098,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(Block, 48); - static_assert_size!(Expr<'_>, 64); + static_assert_size!(Expr<'_>, 72); static_assert_size!(ExprKind<'_>, 40); static_assert_size!(Pat<'_>, 64); static_assert_size!(PatKind<'_>, 48); diff --git a/compiler/rustc_middle/src/ty/rvalue_scopes.rs b/compiler/rustc_middle/src/ty/rvalue_scopes.rs index 37dcf7c0d64..57c2d7623d2 100644 --- a/compiler/rustc_middle/src/ty/rvalue_scopes.rs +++ b/compiler/rustc_middle/src/ty/rvalue_scopes.rs @@ -18,15 +18,17 @@ impl RvalueScopes { } /// Returns the scope when the temp created by `expr_id` will be cleaned up. + /// It also emits a lint on potential backwards incompatible change to the temporary scope + /// which is *for now* always shortening. pub fn temporary_scope( &self, region_scope_tree: &ScopeTree, expr_id: hir::ItemLocalId, - ) -> Option { + ) -> (Option, Option) { // Check for a designated rvalue scope. if let Some(&s) = self.map.get(&expr_id) { debug!("temporary_scope({expr_id:?}) = {s:?} [custom]"); - return s; + return (s, None); } // Otherwise, locate the innermost terminating scope @@ -34,27 +36,40 @@ impl RvalueScopes { // have an enclosing scope, hence no scope will be // returned. let mut id = Scope { id: expr_id, data: ScopeData::Node }; + let mut backwards_incompatible = None; while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) { match p.data { ScopeData::Destruction => { debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]"); - return Some(id); + return (Some(id), backwards_incompatible); } ScopeData::IfThenRescope => { debug!("temporary_scope({expr_id:?}) = {p:?} [enclosing]"); - return Some(p); + return (Some(p), backwards_incompatible); } ScopeData::Node | ScopeData::CallSite | ScopeData::Arguments | ScopeData::IfThen - | ScopeData::Remainder(_) => id = p, + | ScopeData::Remainder(_) => { + // If we haven't already passed through a backwards-incompatible node, + // then check if we are passing through one now and record it if so. + // This is for now only working for cases where a temporary lifetime is + // *shortened*. + if backwards_incompatible.is_none() { + backwards_incompatible = region_scope_tree + .backwards_incompatible_scope + .get(&p.item_local_id()) + .copied(); + } + id = p + } } } debug!("temporary_scope({expr_id:?}) = None"); - None + (None, backwards_incompatible) } /// Make an association between a sub-expression and an extended lifetime diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 159959d4f1f..0cab853196b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -1,6 +1,5 @@ //! See docs in build/expr/mod.rs -use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::*; use tracing::{debug, instrument}; @@ -9,6 +8,12 @@ use crate::build::expr::category::Category; use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary}; impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Construct a temporary lifetime restricted to just the local scope + pub(crate) fn local_temp_lifetime(&self) -> TempLifetime { + let local_scope = self.local_scope(); + TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None } + } + /// Returns an operand suitable for use until the end of the current /// scope expression. /// @@ -21,8 +26,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, expr_id: ExprId, ) -> BlockAnd> { - let local_scope = self.local_scope(); - self.as_operand(block, Some(local_scope), expr_id, LocalInfo::Boring, NeedsTemporary::Maybe) + self.as_operand( + block, + self.local_temp_lifetime(), + expr_id, + LocalInfo::Boring, + NeedsTemporary::Maybe, + ) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -80,8 +90,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, expr: ExprId, ) -> BlockAnd> { - let local_scope = self.local_scope(); - self.as_call_operand(block, Some(local_scope), expr) + self.as_call_operand(block, self.local_temp_lifetime(), expr) } /// Compile `expr` into a value that can be used as an operand. @@ -102,7 +111,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_operand( &mut self, mut block: BasicBlock, - scope: Option, + scope: TempLifetime, expr_id: ExprId, local_info: LocalInfo<'tcx>, needs_temporary: NeedsTemporary, @@ -146,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_call_operand( &mut self, mut block: BasicBlock, - scope: Option, + scope: TempLifetime, expr_id: ExprId, ) -> BlockAnd> { let this = self; diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 9f6e0735b48..6ce88cdc39d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -6,7 +6,6 @@ use std::iter; use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; use rustc_hir::def_id::LocalDefId; use rustc_middle::hir::place::{Projection as HirProjection, ProjectionKind as HirProjectionKind}; -use rustc_middle::middle::region; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -598,7 +597,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { index: ExprId, mutability: Mutability, fake_borrow_temps: Option<&mut Vec>, - temp_lifetime: Option, + temp_lifetime: TempLifetime, expr_span: Span, source_info: SourceInfo, ) -> BlockAnd> { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index a3fee38908b..3f89e337781 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -33,14 +33,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_id: ExprId, ) -> BlockAnd> { let local_scope = self.local_scope(); - self.as_rvalue(block, Some(local_scope), expr_id) + self.as_rvalue( + block, + TempLifetime { temp_lifetime: Some(local_scope), backwards_incompatible: None }, + expr_id, + ) } /// Compile `expr`, yielding an rvalue. pub(crate) fn as_rvalue( &mut self, mut block: BasicBlock, - scope: Option, + scope: TempLifetime, expr_id: ExprId, ) -> BlockAnd> { let this = self; @@ -171,7 +175,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, kind: StatementKind::StorageLive(result), }); - if let Some(scope) = scope { + if let Some(scope) = scope.temp_lifetime { // schedule a shallow free of that memory, lest we unwind: this.schedule_drop_storage_and_value(expr_span, scope, result); } @@ -445,7 +449,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.limit_capture_mutability( upvar_expr.span, upvar_expr.ty, - scope, + scope.temp_lifetime, block, arg, ) @@ -705,7 +709,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, value: ExprId, - scope: Option, + scope: TempLifetime, outer_source_info: SourceInfo, ) -> BlockAnd> { let this = self; diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index b8b5e4634ed..466f67b1ba4 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -2,7 +2,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::HirId; -use rustc_middle::middle::region; use rustc_middle::middle::region::{Scope, ScopeData}; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -17,7 +16,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn as_temp( &mut self, block: BasicBlock, - temp_lifetime: Option, + temp_lifetime: TempLifetime, expr_id: ExprId, mutability: Mutability, ) -> BlockAnd { @@ -31,7 +30,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn as_temp_inner( &mut self, mut block: BasicBlock, - temp_lifetime: Option, + temp_lifetime: TempLifetime, expr_id: ExprId, mutability: Mutability, ) -> BlockAnd { @@ -47,8 +46,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let expr_ty = expr.ty; - let deduplicate_temps = - this.fixed_temps_scope.is_some() && this.fixed_temps_scope == temp_lifetime; + let deduplicate_temps = this.fixed_temps_scope.is_some() + && this.fixed_temps_scope == temp_lifetime.temp_lifetime; let temp = if deduplicate_temps && let Some(temp_index) = this.fixed_temps.get(&expr_id) { *temp_index } else { @@ -76,7 +75,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { LocalInfo::BlockTailTemp(tail_info) } - _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = temp_lifetime => { + _ if let Some(Scope { data: ScopeData::IfThenRescope, id }) = + temp_lifetime.temp_lifetime => + { LocalInfo::IfThenRescopeTemp { if_then: HirId { owner: this.hir_id.owner, local_id: id }, } @@ -117,7 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Anything with a shorter lifetime (e.g the `&foo()` in // `bar(&foo())` or anything within a block will keep the // regular drops just like runtime code. - if let Some(temp_lifetime) = temp_lifetime { + if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Storage); } } @@ -125,10 +126,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = this.expr_into_dest(temp_place, block, expr_id).into_block(); - if let Some(temp_lifetime) = temp_lifetime { + if let Some(temp_lifetime) = temp_lifetime.temp_lifetime { this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); } + if let Some(backwards_incompatible) = temp_lifetime.backwards_incompatible { + this.schedule_backwards_incompatible_drop(expr_span, backwards_incompatible, temp); + } + block.and(temp) } } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 0dec56d21ae..bebb44faba6 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -139,7 +139,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (#66975) Source could be a const of type `!`, so has to // exist in the generated MIR. unpack!( - block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut) + block = + this.as_temp(block, this.local_temp_lifetime(), source, Mutability::Mut) ); // This is an optimization. If the expression was a call then we already have an @@ -321,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let is_union = adt_def.is_union(); let active_field_index = is_union.then(|| fields[0].name); - let scope = this.local_scope(); + let scope = this.local_temp_lifetime(); // first process the set of fields that were provided // (evaluating them in order given by user) @@ -333,7 +334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unpack!( block = this.as_operand( block, - Some(scope), + scope, f.expr, LocalInfo::AggregateTemp, NeedsTemporary::Maybe, @@ -548,15 +549,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Yield { value } => { - let scope = this.local_scope(); + let scope = this.local_temp_lifetime(); let value = unpack!( - block = this.as_operand( - block, - Some(scope), - value, - LocalInfo::Boring, - NeedsTemporary::No - ) + block = + this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No) ); let resume = this.cfg.start_new_block(); this.cfg.terminate(block, source_info, TerminatorKind::Yield { diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 02ca12028d3..15ee6dd014c 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -172,8 +172,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None }; - let temp = - unpack!(block = this.as_temp(block, statement_scope, expr_id, Mutability::Not)); + let temp = unpack!( + block = this.as_temp( + block, + TempLifetime { + temp_lifetime: statement_scope, + backwards_incompatible: None + }, + expr_id, + Mutability::Not + ) + ); if let Some(span) = adjusted_span { this.local_decls[temp].source_info.span = span; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a62d4e9d873..a4d16295880 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -202,8 +202,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Increment the decision depth, in case we encounter boolean expressions // further down. this.mcdc_increment_depth_if_enabled(); - let place = - unpack!(block = this.as_temp(block, Some(temp_scope), expr_id, mutability)); + let place = unpack!( + block = this.as_temp( + block, + TempLifetime { + temp_lifetime: Some(temp_scope), + backwards_incompatible: None + }, + expr_id, + mutability + ) + ); this.mcdc_decrement_depth_if_enabled(); let operand = Operand::Move(Place::from(place)); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index e63fbeeac66..636e47b7ad2 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -89,7 +89,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::thir::{ExprId, LintLevel}; -use rustc_middle::{bug, span_bug}; +use rustc_middle::{bug, span_bug, ty}; use rustc_session::lint::Level; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span}; @@ -151,6 +151,9 @@ struct DropData { /// Whether this is a value Drop or a StorageDead. kind: DropKind, + + /// Whether this is a backwards-incompatible drop lint + backwards_incompatible_lint: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -274,8 +277,12 @@ impl DropTree { // represents the block in the tree that should be jumped to once all // of the required drops have been performed. let fake_source_info = SourceInfo::outermost(DUMMY_SP); - let fake_data = - DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage }; + let fake_data = DropData { + source_info: fake_source_info, + local: Local::MAX, + kind: DropKind::Storage, + backwards_incompatible_lint: false, + }; let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]); Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() } } @@ -763,7 +770,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local = place.as_local().unwrap_or_else(|| bug!("projection in tail call args")); - Some(DropData { source_info, local, kind: DropKind::Value }) + Some(DropData { + source_info, + local, + kind: DropKind::Value, + backwards_incompatible_lint: false, + }) } Operand::Constant(_) => None, }) @@ -1019,9 +1031,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if local.index() <= self.arg_count { span_bug!( span, - "`schedule_drop` called with local {:?} and arg_count {}", + "`schedule_drop` called with body argument {:?} \ + but its storage does not require a drop", local, - self.arg_count, ) } false @@ -1089,6 +1101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, local, kind: drop_kind, + backwards_incompatible_lint: false, }); return; @@ -1098,6 +1111,45 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } + /// Schedule emission of a backwards incompatible drop lint hint. + /// Applicable only to temporary values for now. + pub(crate) fn schedule_backwards_incompatible_drop( + &mut self, + span: Span, + region_scope: region::Scope, + local: Local, + ) { + if !self.local_decls[local].ty.has_significant_drop(self.tcx, ty::TypingEnv { + typing_mode: ty::TypingMode::non_body_analysis(), + param_env: self.param_env, + }) { + return; + } + for scope in self.scopes.scopes.iter_mut().rev() { + // Since we are inserting linting MIR statement, we have to invalidate the caches + scope.invalidate_cache(); + if scope.region_scope == region_scope { + let region_scope_span = region_scope.span(self.tcx, self.region_scope_tree); + let scope_end = self.tcx.sess.source_map().end_point(region_scope_span); + + scope.drops.push(DropData { + source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, + local, + kind: DropKind::Value, + backwards_incompatible_lint: true, + }); + + return; + } + } + span_bug!( + span, + "region scope {:?} not in scope to drop {:?} for linting", + region_scope, + local + ); + } + /// Indicates that the "local operand" stored in `local` is /// *moved* at some point during execution (see `local_scope` for /// more information about what a "local operand" is -- in short, @@ -1378,16 +1430,25 @@ fn build_scope_drops<'tcx>( continue; } - unwind_drops.add_entry_point(block, unwind_to); - - let next = cfg.start_new_block(); - cfg.terminate(block, source_info, TerminatorKind::Drop { - place: local.into(), - target: next, - unwind: UnwindAction::Continue, - replace: false, - }); - block = next; + if drop_data.backwards_incompatible_lint { + cfg.push(block, Statement { + source_info, + kind: StatementKind::BackwardIncompatibleDropHint { + place: Box::new(local.into()), + reason: BackwardIncompatibleDropReason::Edition2024, + }, + }); + } else { + unwind_drops.add_entry_point(block, unwind_to); + let next = cfg.start_new_block(); + cfg.terminate(block, source_info, TerminatorKind::Drop { + place: local.into(), + target: next, + unwind: UnwindAction::Continue, + replace: false, + }); + block = next; + } } DropKind::Storage => { if storage_dead_on_unwind { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 198fa4ffb7a..47b7f332951 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -23,7 +23,6 @@ use tracing::{debug, info, instrument, trace}; use crate::errors; use crate::thir::cx::Cx; -use crate::thir::cx::region::Scope; use crate::thir::util::UserAnnotatedTyHelpers; impl<'tcx> Cx<'tcx> { @@ -240,7 +239,7 @@ impl<'tcx> Cx<'tcx> { fn mirror_expr_cast( &mut self, source: &'tcx hir::Expr<'tcx>, - temp_lifetime: Option, + temp_lifetime: TempLifetime, span: Span, ) -> ExprKind<'tcx> { let tcx = self.tcx; @@ -325,7 +324,7 @@ impl<'tcx> Cx<'tcx> { fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); - let temp_lifetime = + let (temp_lifetime, backwards_incompatible) = self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let kind = match expr.kind { @@ -361,7 +360,7 @@ impl<'tcx> Cx<'tcx> { let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)); let tupled_args = Expr { ty: Ty::new_tup_from_iter(tcx, arg_tys), - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, span: expr.span, kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, }; @@ -391,7 +390,10 @@ impl<'tcx> Cx<'tcx> { && let [value] = args { return Expr { - temp_lifetime, + temp_lifetime: TempLifetime { + temp_lifetime, + backwards_incompatible, + }, ty: expr_ty, span: expr.span, kind: ExprKind::Box { value: self.mirror_expr(value) }, @@ -811,13 +813,13 @@ impl<'tcx> Cx<'tcx> { }, hir::ExprKind::Loop(body, ..) => { let block_ty = self.typeck_results().node_type(body.hir_id); - let temp_lifetime = self + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, body.hir_id.local_id); let block = self.mirror_block(body); let body = self.thir.exprs.push(Expr { ty: block_ty, - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, span: self.thir[block].span, kind: ExprKind::Block { block }, }); @@ -838,13 +840,17 @@ impl<'tcx> Cx<'tcx> { expr, cast_ty.hir_id, user_ty, ); - let cast = self.mirror_expr_cast(source, temp_lifetime, expr.span); + let cast = self.mirror_expr_cast( + source, + TempLifetime { temp_lifetime, backwards_incompatible }, + expr.span, + ); if let Some(user_ty) = user_ty { // NOTE: Creating a new Expr and wrapping a Cast inside of it may be // inefficient, revisit this when performance becomes an issue. let cast_expr = self.thir.exprs.push(Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: expr_ty, span: expr.span, kind: cast, @@ -887,7 +893,12 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"), }; - Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } + Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: expr_ty, + span: expr.span, + kind, + } } fn user_args_applied_to_res( @@ -931,7 +942,7 @@ impl<'tcx> Cx<'tcx> { span: Span, overloaded_callee: Option>, ) -> Expr<'tcx> { - let temp_lifetime = + let (temp_lifetime, backwards_incompatible) = self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let (ty, user_ty) = match overloaded_callee { Some(fn_def) => (fn_def, None), @@ -952,7 +963,12 @@ impl<'tcx> Cx<'tcx> { ) } }; - Expr { temp_lifetime, ty, span, kind: ExprKind::ZstLiteral { user_ty } } + Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty, + span, + kind: ExprKind::ZstLiteral { user_ty }, + } } fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { @@ -1025,7 +1041,7 @@ impl<'tcx> Cx<'tcx> { Res::Def(DefKind::Static { .. }, id) => { // this is &raw for extern static or static mut, and & for other statics let ty = self.tcx.static_ptr_ty(id, self.typing_env()); - let temp_lifetime = self + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let kind = if self.tcx.is_thread_local_static(id) { @@ -1035,7 +1051,12 @@ impl<'tcx> Cx<'tcx> { ExprKind::StaticRef { alloc_id, ty, def_id: id } }; ExprKind::Deref { - arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }), + arg: self.thir.exprs.push(Expr { + ty, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + span: expr.span, + kind, + }), } } @@ -1106,13 +1127,13 @@ impl<'tcx> Cx<'tcx> { // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type - let temp_lifetime = + let (temp_lifetime, backwards_incompatible) = self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); let fun = self.method_callee(expr, span, overloaded_callee); let fun = self.thir.exprs.push(fun); let fun_ty = self.thir[fun].ty; let ref_expr = self.thir.exprs.push(Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: ref_ty, span, kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span }, @@ -1127,7 +1148,7 @@ impl<'tcx> Cx<'tcx> { closure_expr: &'tcx hir::Expr<'tcx>, place: HirPlace<'tcx>, ) -> Expr<'tcx> { - let temp_lifetime = self + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id); let var_ty = place.base_ty; @@ -1143,7 +1164,7 @@ impl<'tcx> Cx<'tcx> { }; let mut captured_place_expr = Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: var_ty, span: closure_expr.span, kind: self.convert_var(var_hir_id), @@ -1168,8 +1189,12 @@ impl<'tcx> Cx<'tcx> { } }; - captured_place_expr = - Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }; + captured_place_expr = Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: proj.ty, + span: closure_expr.span, + kind, + }; } captured_place_expr @@ -1184,7 +1209,7 @@ impl<'tcx> Cx<'tcx> { let upvar_capture = captured_place.info.capture_kind; let captured_place_expr = self.convert_captured_hir_place(closure_expr, captured_place.place.clone()); - let temp_lifetime = self + let (temp_lifetime, backwards_incompatible) = self .rvalue_scopes .temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id); @@ -1201,7 +1226,7 @@ impl<'tcx> Cx<'tcx> { } }; Expr { - temp_lifetime, + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, ty: upvar_ty, span: closure_expr.span, kind: ExprKind::Borrow { diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index e06c1f2bb49..fd7254a0210 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -253,6 +253,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => None, }; if let Some(destination) = destination { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index c5fd2a631ff..576289e228a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -157,6 +157,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { | StatementKind::Nop | StatementKind::Retag(..) | StatementKind::Intrinsic(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::StorageLive(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index fd8e403ebc2..0880364bfca 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -385,6 +385,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 9bbfae17fd9..d00bfc66a6a 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -25,6 +25,31 @@ mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspen .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point mir_transform_operation_will_panic = this operation will panic at runtime +mir_transform_tail_expr_drop_order = relative drop order changing in Rust 2024 + .temporaries = in Rust 2024, this temporary value will be dropped first + .observers = in Rust 2024, this local variable or temporary value will be dropped second + .note_dtors = + dropping the temporary value runs this custom `Drop` impl, which we could not prove to be side-effect free + .note_observer_dtors = + dropping the local runs this custom `Drop` impl, which we could not prove to be side-effect free + .drop_location = + now the temporary value is dropped here, before the local variables in the block or statement + .note_epilogue = most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + .label_local_epilogue = {$is_dropped_first_edition_2024 -> + [true] up until Edition 2021 `{$name}` is dropped last but will be dropped earlier in Edition 2024 + *[false] `{$name}` will be dropped later as of Edition 2024 + } + +mir_transform_tail_expr_dtor = {$dtor_kind -> + [dyn] `{$name}` may invoke a custom destructor because it contains a trait object + *[concrete] `{$name}` invokes this custom destructor + } + +mir_transform_tail_expr_local = {$is_generated_name -> + [true] this value will be stored in a temporary; let us call it `{$name}` + *[false] `{$name}` calls a custom destructor + } + mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index d38a1dd11dc..8295a806d71 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1772,6 +1772,7 @@ impl<'tcx> Visitor<'tcx> for EnsureCoroutineFieldAssignmentsNeverAlias<'_> { | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 875db23ce09..824d657e1fc 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -97,6 +97,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option { StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => None, // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead` diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 26480be29f3..d017202f48b 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -186,7 +186,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { | StatementKind::FakeRead(..) | StatementKind::PlaceMention(..) | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) => (), + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::AscribeUserType(..) => {} } } diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 2898f82e25c..0c75cdadc92 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -99,7 +99,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { | StatementKind::Intrinsic(_) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(_) - | StatementKind::Nop => (), + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::Nop => {} StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase!", statement.kind) diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index beeab0d4a66..9c74b2f0839 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -581,7 +581,7 @@ impl WriteInfo { | Rvalue::RawPtr(_, _) | Rvalue::Len(_) | Rvalue::Discriminant(_) - | Rvalue::CopyForDeref(_) => (), + | Rvalue::CopyForDeref(_) => {} } } // Retags are technically also reads, but reporting them as a write suffices @@ -596,7 +596,8 @@ impl WriteInfo { | StatementKind::Coverage(_) | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) - | StatementKind::PlaceMention(_) => (), + | StatementKind::BackwardIncompatibleDropHint { .. } + | StatementKind::PlaceMention(_) => {} StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { bug!("{:?} not found in this MIR phase", statement) } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 5c2c36db0f7..beed007589b 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -352,6 +352,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { | StatementKind::FakeRead(..) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => None, } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5651bf469d5..bfb842e4485 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -50,6 +50,7 @@ mod deduce_param_attrs; mod errors; mod ffi_unwind_calls; mod lint; +mod lint_tail_expr_drop_order; mod shim; mod ssa; @@ -490,6 +491,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & } let (body, _) = tcx.mir_promoted(def); + lint_tail_expr_drop_order::run_lint(tcx, def, &body.borrow()); let mut body = body.steal(); if let Some(error_reported) = tainted_by_errors { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs new file mode 100644 index 00000000000..b8502fcbafb --- /dev/null +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -0,0 +1,701 @@ +use std::cell::RefCell; +use std::collections::hash_map; +use std::rc::Rc; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_errors::Subdiagnostic; +use rustc_hir::CRATE_HIR_ID; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::{IndexSlice, IndexVec}; +use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_middle::bug; +use rustc_middle::mir::{ + self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind, + dump_mir, +}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; +use rustc_mir_dataflow::{Analysis, MaybeReachable, ResultsCursor}; +use rustc_session::lint::builtin::TAIL_EXPR_DROP_ORDER; +use rustc_session::lint::{self}; +use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_type_ir::data_structures::IndexMap; +use smallvec::{SmallVec, smallvec}; +use tracing::{debug, instrument}; + +fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool { + left.local == right.local + && left.projection.iter().zip(right.projection).all(|(left, right)| left == right) +} + +/// Cache entry of `drop` at a `BasicBlock` +#[derive(Debug, Clone, Copy)] +enum MovePathIndexAtBlock { + /// We know nothing yet + Unknown, + /// We know that the `drop` here has no effect + None, + /// We know that the `drop` here will invoke a destructor + Some(MovePathIndex), +} + +struct DropsReachable<'a, 'mir, 'tcx> { + body: &'a Body<'tcx>, + place: &'a Place<'tcx>, + drop_span: &'a mut Option, + move_data: &'a MoveData<'tcx>, + maybe_init: &'a mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + block_drop_value_info: &'a mut IndexSlice, + collected_drops: &'a mut ChunkedBitSet, + visited: FxHashMap>>>, +} + +impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { + fn visit(&mut self, block: BasicBlock) { + let move_set_size = self.move_data.move_paths.len(); + let make_new_path_set = || Rc::new(RefCell::new(ChunkedBitSet::new_empty(move_set_size))); + + let data = &self.body.basic_blocks[block]; + let Some(terminator) = &data.terminator else { return }; + // Given that we observe these dropped locals here at `block` so far, + // we will try to update the successor blocks. + // An occupied entry at `block` in `self.visited` signals that we have visited `block` before. + let dropped_local_here = + Rc::clone(self.visited.entry(block).or_insert_with(make_new_path_set)); + // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately it is expensive. + // Let's cache them in `self.block_drop_value_info`. + match self.block_drop_value_info[block] { + MovePathIndexAtBlock::Some(dropped) => { + dropped_local_here.borrow_mut().insert(dropped); + } + MovePathIndexAtBlock::Unknown => { + if let TerminatorKind::Drop { place, .. } = &terminator.kind + && let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) = + self.move_data.rev_lookup.find(place.as_ref()) + { + // Since we are working with MIRs at a very early stage, + // observing a `drop` terminator is not indicative enough that + // the drop will definitely happen. + // That is decided in the drop elaboration pass instead. + // Therefore, we need to consult with the maybe-initialization information. + self.maybe_init.seek_before_primary_effect(Location { + block, + statement_index: data.statements.len(), + }); + + // Check if the drop of `place` under inspection is really in effect. + // This is true only when `place` may have been initialized along a control flow path from a BID to the drop program point today. + // In other words, this is where the drop of `place` will happen in the future instead. + if let MaybeReachable::Reachable(maybe_init) = self.maybe_init.get() + && maybe_init.contains(idx) + { + // We also cache the drop information, so that we do not need to check on data-flow cursor again + self.block_drop_value_info[block] = MovePathIndexAtBlock::Some(idx); + dropped_local_here.borrow_mut().insert(idx); + } else { + self.block_drop_value_info[block] = MovePathIndexAtBlock::None; + } + } + } + MovePathIndexAtBlock::None => {} + } + + for succ in terminator.successors() { + let target = &self.body.basic_blocks[succ]; + if target.is_cleanup { + continue; + } + + // As long as we are passing through a new block, or new dropped places to propagate, + // we will proceed with `succ` + let dropped_local_there = match self.visited.entry(succ) { + hash_map::Entry::Occupied(occupied_entry) => { + if succ == block + || !occupied_entry.get().borrow_mut().union(&*dropped_local_here.borrow()) + { + // `succ` has been visited but no new drops observed so far, + // so we can bail on `succ` until new drop information arrives + continue; + } + Rc::clone(occupied_entry.get()) + } + hash_map::Entry::Vacant(vacant_entry) => Rc::clone( + vacant_entry.insert(Rc::new(RefCell::new(dropped_local_here.borrow().clone()))), + ), + }; + if let Some(terminator) = &target.terminator + && let TerminatorKind::Drop { + place: dropped_place, + target: _, + unwind: _, + replace: _, + } = &terminator.kind + && place_has_common_prefix(dropped_place, self.place) + { + // We have now reached the current drop of the `place`. + // Let's check the observed dropped places in. + self.collected_drops.union(&*dropped_local_there.borrow()); + if self.drop_span.is_none() { + // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are still a bit wonky. + // There is a high chance that this span still points to a block rather than a statement semicolon. + *self.drop_span = Some(terminator.source_info.span); + } + // Now we have discovered a simple control flow path from a future drop point + // to the current drop point. + // We will not continue from there. + } else { + self.visit(succ) + } + } + } +} + +/// An additional filter to exclude well-known types from the ecosystem +/// because their drops are trivial. +/// This returns additional types to check if the drops are delegated to those. +/// A typical example is `hashbrown::HashMap`, whose drop is delegated to `K` and `V`. +fn true_significant_drop_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option; 2]>> { + if let ty::Adt(def, args) = ty.kind() { + let mut did = def.did(); + let mut name_rev = vec![]; + loop { + let key = tcx.def_key(did); + + match key.disambiguated_data.data { + rustc_hir::definitions::DefPathData::CrateRoot => { + name_rev.push(tcx.crate_name(did.krate)) + } + rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol), + _ => return None, + } + if let Some(parent) = key.parent { + did = DefId { krate: did.krate, index: parent }; + } else { + break; + } + } + let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect(); + debug!(?name_str); + match name_str[..] { + // These are the types from Rust core ecosystem + ["sym" | "proc_macro2", ..] + | ["core" | "std", "task", "LocalWaker" | "Waker"] + | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]), + // These are important types from Rust ecosystem + ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]), + ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => { + if let [ty, ..] = &***args + && let Some(ty) = ty.as_type() + { + Some(smallvec![ty]) + } else { + None + } + } + ["hashbrown", "raw", "RawDrain"] => { + if let [_, ty, ..] = &***args + && let Some(ty) = ty.as_type() + { + Some(smallvec![ty]) + } else { + None + } + } + _ => None, + } + } else { + None + } +} + +/// Returns the list of types with a "potentially sigificant" that may be dropped +/// by dropping a value of type `ty`. +#[instrument(level = "debug", skip(tcx, param_env))] +fn extract_component_raw<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ty_seen: &mut UnordSet>, +) -> SmallVec<[Ty<'tcx>; 4]> { + // Droppiness does not depend on regions, so let us erase them. + let ty = tcx + .try_normalize_erasing_regions( + ty::TypingEnv { param_env, typing_mode: ty::TypingMode::PostAnalysis }, + ty, + ) + .unwrap_or(ty); + + let tys = tcx.list_significant_drop_tys(param_env.and(ty)); + debug!(?ty, "components"); + let mut out_tys = smallvec![]; + for ty in tys { + if let Some(tys) = true_significant_drop_ty(tcx, ty) { + // Some types can be further opened up because the drop is simply delegated + for ty in tys { + if ty_seen.insert(ty) { + out_tys.extend(extract_component_raw(tcx, param_env, ty, ty_seen)); + } + } + } else { + if ty_seen.insert(ty) { + out_tys.push(ty); + } + } + } + out_tys +} + +#[instrument(level = "debug", skip(tcx, param_env))] +fn extract_component_with_significant_dtor<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> SmallVec<[Ty<'tcx>; 4]> { + let mut tys = extract_component_raw(tcx, param_env, ty, &mut Default::default()); + let mut deduplicate = FxHashSet::default(); + tys.retain(|oty| deduplicate.insert(*oty)); + tys.into_iter().collect() +} + +/// Extract the span of the custom destructor of a type +/// especially the span of the `impl Drop` header or its entire block +/// when we are working with current local crate. +#[instrument(level = "debug", skip(tcx))] +fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { + match ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Error(_) + | ty::Str + | ty::Never + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnPtr(_, _) + | ty::Tuple(_) + | ty::Dynamic(_, _, _) + | ty::Alias(_, _) + | ty::Bound(_, _) + | ty::Pat(_, _) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Slice(_) + | ty::Array(_, _) => None, + ty::Adt(adt_def, _) => { + let did = adt_def.did(); + let try_local_did_span = |did: DefId| { + if let Some(local) = did.as_local() { + tcx.source_span(local) + } else { + tcx.def_span(did) + } + }; + let dtor = if let Some(dtor) = tcx.adt_destructor(did) { + dtor.did + } else if let Some(dtor) = tcx.adt_async_destructor(did) { + dtor.future + } else { + return Some(try_local_did_span(did)); + }; + let def_key = tcx.def_key(dtor); + let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) }; + let parent_did = DefId { index: parent_index, krate: dtor.krate }; + Some(try_local_did_span(parent_did)) + } + ty::Coroutine(did, _) + | ty::CoroutineWitness(did, _) + | ty::CoroutineClosure(did, _) + | ty::Closure(did, _) + | ty::FnDef(did, _) + | ty::Foreign(did) => Some(tcx.def_span(did)), + ty::Param(_) => None, + } +} + +/// Check if a moved place at `idx` is a part of a BID. +/// The use of this check is that we will consider drops on these +/// as a drop of the overall BID and, thus, we can exclude it from the diagnosis. +fn place_descendent_of_bids<'tcx>( + mut idx: MovePathIndex, + move_data: &MoveData<'tcx>, + bids: &UnordSet<&Place<'tcx>>, +) -> bool { + loop { + let path = &move_data.move_paths[idx]; + if bids.contains(&path.place) { + return true; + } + if let Some(parent) = path.parent { + idx = parent; + } else { + return false; + } + } +} + +/// The core of the lint `tail-expr-drop-order` +pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) { + if matches!(tcx.def_kind(def_id), rustc_hir::def::DefKind::SyntheticCoroutineBody) { + // A synthetic coroutine has no HIR body and it is enough to just analyse the original body + return; + } + if body.span.edition().at_least_rust_2024() + || tcx.lints_that_dont_need_to_run(()).contains(&lint::LintId::of(TAIL_EXPR_DROP_ORDER)) + { + return; + } + // ## About BIDs in blocks ## + // Track the set of blocks that contain a backwards-incompatible drop (BID) + // and, for each block, the vector of locations. + // + // We group them per-block because they tend to scheduled in the same drop ladder block. + let mut bid_per_block = IndexMap::default(); + let mut bid_places = UnordSet::new(); + let param_env = tcx.param_env(def_id).with_reveal_all_normalized(tcx); + let mut ty_dropped_components = UnordMap::default(); + for (block, data) in body.basic_blocks.iter_enumerated() { + for (statement_index, stmt) in data.statements.iter().enumerate() { + if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = &stmt.kind { + let ty = place.ty(body, tcx).ty; + if ty_dropped_components + .entry(ty) + .or_insert_with(|| extract_component_with_significant_dtor(tcx, param_env, ty)) + .is_empty() + { + continue; + } + bid_per_block + .entry(block) + .or_insert(vec![]) + .push((Location { block, statement_index }, &**place)); + bid_places.insert(&**place); + } + } + } + if bid_per_block.is_empty() { + return; + } + + dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, |_, _| Ok(())); + let locals_with_user_names = collect_user_names(body); + let is_closure_like = tcx.is_closure_like(def_id.to_def_id()); + + // Compute the "maybe initialized" information for this body. + // When we encounter a DROP of some place P we only care + // about the drop if `P` may be initialized. + let move_data = MoveData::gather_moves(body, tcx, |_| true); + let maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data); + let mut maybe_init = maybe_init.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body); + let mut block_drop_value_info = + IndexVec::from_elem_n(MovePathIndexAtBlock::Unknown, body.basic_blocks.len()); + for (&block, candidates) in &bid_per_block { + // We will collect drops on locals on paths between BID points to their actual drop locations + // into `all_locals_dropped`. + let mut all_locals_dropped = ChunkedBitSet::new_empty(move_data.move_paths.len()); + let mut drop_span = None; + for &(_, place) in candidates.iter() { + let mut collected_drops = ChunkedBitSet::new_empty(move_data.move_paths.len()); + // ## On detecting change in relative drop order ## + // Iterate through each BID-containing block `block`. + // If the place `P` targeted by the BID is "maybe initialized", + // then search forward to find the actual `DROP(P)` point. + // Everything dropped between the BID and the actual drop point + // is something whose relative drop order will change. + DropsReachable { + body, + place, + drop_span: &mut drop_span, + move_data: &move_data, + maybe_init: &mut maybe_init, + block_drop_value_info: &mut block_drop_value_info, + collected_drops: &mut collected_drops, + visited: Default::default(), + } + .visit(block); + // Compute the set `all_locals_dropped` of local variables that are dropped + // after the BID point but before the current drop point. + // + // These are the variables whose drop impls will be reordered with respect + // to `place`. + all_locals_dropped.union(&collected_drops); + } + + // We shall now exclude some local bindings for the following cases. + { + let mut to_exclude = ChunkedBitSet::new_empty(all_locals_dropped.domain_size()); + // We will now do subtraction from the candidate dropped locals, because of the following reasons. + for path_idx in all_locals_dropped.iter() { + let move_path = &move_data.move_paths[path_idx]; + let dropped_local = move_path.place.local; + // a) A return value _0 will eventually be used + // Example: + // fn f() -> Droppy { + // let _x = Droppy; + // Droppy + // } + // _0 holds the literal `Droppy` and rightfully `_x` has to be dropped first + if dropped_local == Local::ZERO { + debug!(?dropped_local, "skip return value"); + to_exclude.insert(path_idx); + continue; + } + // b) If we are analysing a closure, the captures are still dropped last. + // This is part of the closure capture lifetime contract. + // They are similar to the return value _0 with respect to lifetime rules. + if is_closure_like && matches!(dropped_local, ty::CAPTURE_STRUCT_LOCAL) { + debug!(?dropped_local, "skip closure captures"); + to_exclude.insert(path_idx); + continue; + } + // c) Sometimes we collect places that are projections into the BID locals, + // so they are considered dropped now. + // Example: + // struct NotVeryDroppy(Droppy); + // impl Drop for Droppy {..} + // fn f() -> NotVeryDroppy { + // let x = NotVeryDroppy(droppy()); + // { + // let y: Droppy = x.0; + // NotVeryDroppy(y) + // } + // } + // `y` takes `x.0`, which invalidates `x` as a complete `NotVeryDroppy` + // so there is no point in linting against `x` any more. + if place_descendent_of_bids(path_idx, &move_data, &bid_places) { + debug!(?dropped_local, "skip descendent of bids"); + to_exclude.insert(path_idx); + continue; + } + let observer_ty = move_path.place.ty(body, tcx).ty; + // d) The collected local has no custom destructor that passes our ecosystem filter. + if ty_dropped_components + .entry(observer_ty) + .or_insert_with(|| { + extract_component_with_significant_dtor(tcx, param_env, observer_ty) + }) + .is_empty() + { + debug!(?dropped_local, "skip non-droppy types"); + to_exclude.insert(path_idx); + continue; + } + } + // Suppose that all BIDs point into the same local, + // we can remove the this local from the observed drops, + // so that we can focus our diagnosis more on the others. + if candidates.iter().all(|&(_, place)| candidates[0].1.local == place.local) { + for path_idx in all_locals_dropped.iter() { + if move_data.move_paths[path_idx].place.local == candidates[0].1.local { + to_exclude.insert(path_idx); + } + } + } + all_locals_dropped.subtract(&to_exclude); + } + if all_locals_dropped.is_empty() { + // No drop effect is observable, so let us move on. + continue; + } + + // ## The final work to assemble the diagnosis ## + // First collect or generate fresh names for local variable bindings and temporary values. + let local_names = assign_observables_names( + all_locals_dropped + .iter() + .map(|path_idx| move_data.move_paths[path_idx].place.local) + .chain(candidates.iter().map(|(_, place)| place.local)), + &locals_with_user_names, + ); + + let mut lint_root = None; + let mut local_labels = vec![]; + // We now collect the types with custom destructors. + for &(_, place) in candidates { + let linted_local_decl = &body.local_decls[place.local]; + let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else { + bug!("a name should have been assigned") + }; + let name = name.as_str(); + + if lint_root.is_none() + && let ClearCrossCrate::Set(data) = + &body.source_scopes[linted_local_decl.source_info.scope].local_data + { + lint_root = Some(data.lint_root); + } + + // Collect spans of the custom destructors. + let mut seen_dyn = false; + let destructors = ty_dropped_components + .get(&linted_local_decl.ty) + .unwrap() + .iter() + .filter_map(|&ty| { + if let Some(span) = ty_dtor_span(tcx, ty) { + Some(DestructorLabel { span, name, dtor_kind: "concrete" }) + } else if matches!(ty.kind(), ty::Dynamic(..)) { + if seen_dyn { + None + } else { + seen_dyn = true; + Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" }) + } + } else { + None + } + }) + .collect(); + local_labels.push(LocalLabel { + span: linted_local_decl.source_info.span, + destructors, + name, + is_generated_name, + is_dropped_first_edition_2024: true, + }); + } + + // Similarly, custom destructors of the observed drops. + for path_idx in all_locals_dropped.iter() { + let place = &move_data.move_paths[path_idx].place; + // We are not using the type of the local because the drop may be partial. + let observer_ty = place.ty(body, tcx).ty; + + let observer_local_decl = &body.local_decls[place.local]; + let Some(&(ref name, is_generated_name)) = local_names.get(&place.local) else { + bug!("a name should have been assigned") + }; + let name = name.as_str(); + + let mut seen_dyn = false; + let destructors = extract_component_with_significant_dtor(tcx, param_env, observer_ty) + .into_iter() + .filter_map(|ty| { + if let Some(span) = ty_dtor_span(tcx, ty) { + Some(DestructorLabel { span, name, dtor_kind: "concrete" }) + } else if matches!(ty.kind(), ty::Dynamic(..)) { + if seen_dyn { + None + } else { + seen_dyn = true; + Some(DestructorLabel { span: DUMMY_SP, name, dtor_kind: "dyn" }) + } + } else { + None + } + }) + .collect(); + local_labels.push(LocalLabel { + span: observer_local_decl.source_info.span, + destructors, + name, + is_generated_name, + is_dropped_first_edition_2024: false, + }); + } + + let span = local_labels[0].span; + tcx.emit_node_span_lint( + lint::builtin::TAIL_EXPR_DROP_ORDER, + lint_root.unwrap_or(CRATE_HIR_ID), + span, + TailExprDropOrderLint { local_labels, drop_span, _epilogue: () }, + ); + } +} + +/// Extract binding names if available for diagnosis +fn collect_user_names(body: &Body<'_>) -> IndexMap { + let mut names = IndexMap::default(); + for var_debug_info in &body.var_debug_info { + if let mir::VarDebugInfoContents::Place(place) = &var_debug_info.value + && let Some(local) = place.local_or_deref_local() + { + names.entry(local).or_insert(var_debug_info.name); + } + } + names +} + +/// Assign names for anonymous or temporary values for diagnosis +fn assign_observables_names( + locals: impl IntoIterator, + user_names: &IndexMap, +) -> IndexMap { + let mut names = IndexMap::default(); + let mut assigned_names = FxHashSet::default(); + let mut idx = 0u64; + let mut fresh_name = || { + idx += 1; + (format!("#{idx}"), true) + }; + for local in locals { + let name = if let Some(name) = user_names.get(&local) { + let name = name.as_str(); + if assigned_names.contains(name) { fresh_name() } else { (name.to_owned(), false) } + } else { + fresh_name() + }; + assigned_names.insert(name.0.clone()); + names.insert(local, name); + } + names +} + +#[derive(LintDiagnostic)] +#[diag(mir_transform_tail_expr_drop_order)] +struct TailExprDropOrderLint<'a> { + #[subdiagnostic] + local_labels: Vec>, + #[label(mir_transform_drop_location)] + drop_span: Option, + #[note(mir_transform_note_epilogue)] + _epilogue: (), +} + +struct LocalLabel<'a> { + span: Span, + name: &'a str, + is_generated_name: bool, + is_dropped_first_edition_2024: bool, + destructors: Vec>, +} + +/// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order +impl Subdiagnostic for LocalLabel<'_> { + fn add_to_diag_with< + G: rustc_errors::EmissionGuarantee, + F: rustc_errors::SubdiagMessageOp, + >( + self, + diag: &mut rustc_errors::Diag<'_, G>, + f: &F, + ) { + diag.arg("name", self.name); + diag.arg("is_generated_name", self.is_generated_name); + diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); + let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into()); + diag.span_label(self.span, msg); + for dtor in self.destructors { + dtor.add_to_diag_with(diag, f); + } + let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue.into()); + diag.span_label(self.span, msg); + } +} + +#[derive(Subdiagnostic)] +#[note(mir_transform_tail_expr_dtor)] +struct DestructorLabel<'a> { + #[primary_span] + span: Span, + dtor_kind: &'static str, + name: &'a str, +} 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 55394e93a5c..fd49e956f43 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -92,6 +92,7 @@ impl RemoveNoopLandingPads { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => { // These are all noops in a landing pad } diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index 2f723bccc19..6fd70fbe9b0 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -125,6 +125,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { StatementKind::Coverage(_) | StatementKind::Intrinsic(_) | StatementKind::Nop + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::ConstEvalCounter => None, }; if let Some(place_for_ty) = place_for_ty diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 7ed43547e11..4f312ed2aaa 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -523,7 +523,8 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { } StatementKind::SetDiscriminant { ref place, variant_index: _ } - | StatementKind::Deinit(ref place) => { + | StatementKind::Deinit(ref place) + | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } => { self.visit_lhs(place, location); } } @@ -560,6 +561,7 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local), StatementKind::SetDiscriminant { ref place, .. } + | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } | StatementKind::Deinit(ref place) => used_locals.is_used(place.local), StatementKind::Nop => false, _ => true, @@ -587,6 +589,20 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> { self.tcx } + fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { + if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } = + &mut statement.kind + { + self.visit_local( + &mut place.local, + PlaceContext::MutatingUse(MutatingUseContext::Store), + location, + ); + } else { + self.super_statement(statement, location); + } + } + fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { *l = self.map[*l].unwrap(); } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 724238ecfc9..1739fdcc9af 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -343,6 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> { | StatementKind::Intrinsic(_) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } @@ -1493,6 +1494,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | StatementKind::Coverage(_) | StatementKind::ConstEvalCounter | StatementKind::PlaceMention(..) + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 820d8a6be25..fcdf8703b14 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -151,6 +151,10 @@ impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { mir::StatementKind::ConstEvalCounter => { stable_mir::mir::StatementKind::ConstEvalCounter } + // BackwardIncompatibleDropHint has no semantics, so it is translated to Nop. + mir::StatementKind::BackwardIncompatibleDropHint { .. } => { + stable_mir::mir::StatementKind::Nop + } mir::StatementKind::Nop => stable_mir::mir::StatementKind::Nop, } } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 03ab3a55486..469a4ac3e41 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::util::{AlwaysRequiresDrop, needs_drop_components}; use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt}; use rustc_session::Limit; use rustc_span::sym; -use tracing::debug; +use tracing::{debug, instrument}; use crate::errors::NeedsDropOverflow; @@ -23,7 +23,7 @@ fn needs_drop_raw<'tcx>( // needs drop. let adt_has_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant); - let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_dtor, false) + let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_dtor, false, false) .filter(filter_array_elements(tcx, query.typing_env)) .next() .is_some(); @@ -41,7 +41,7 @@ fn needs_async_drop_raw<'tcx>( // it needs async drop. let adt_has_async_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.async_destructor(tcx).map(|_| DtorType::Significant); - let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_async_dtor, false) + let res = drop_tys_helper(tcx, query.value, query.typing_env, adt_has_async_dtor, false, false) .filter(filter_array_elements(tcx, query.typing_env)) .next() .is_some(); @@ -77,6 +77,7 @@ fn has_significant_drop_raw<'tcx>( query.typing_env, adt_consider_insignificant_dtor(tcx), true, + false, ) .filter(filter_array_elements(tcx, query.typing_env)) .next() @@ -88,8 +89,8 @@ fn has_significant_drop_raw<'tcx>( struct NeedsDropTypes<'tcx, F> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - // Whether to reveal coroutine witnesses, this is set - // to `false` unless we compute `needs_drop` for a coroutine witness. + /// Whether to reveal coroutine witnesses, this is set + /// to `false` unless we compute `needs_drop` for a coroutine witness. reveal_coroutine_witnesses: bool, query_ty: Ty<'tcx>, seen_tys: FxHashSet>, @@ -100,6 +101,9 @@ struct NeedsDropTypes<'tcx, F> { unchecked_tys: Vec<(Ty<'tcx>, usize)>, recursion_limit: Limit, adt_components: F, + /// Set this to true if an exhaustive list of types involved in + /// drop obligation is requested. + exhaustive: bool, } impl<'tcx, F> NeedsDropTypes<'tcx, F> { @@ -107,6 +111,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ty: Ty<'tcx>, + exhaustive: bool, adt_components: F, ) -> Self { let mut seen_tys = FxHashSet::default(); @@ -114,14 +119,22 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { Self { tcx, typing_env, - reveal_coroutine_witnesses: false, + reveal_coroutine_witnesses: exhaustive, seen_tys, query_ty: ty, unchecked_tys: vec![(ty, 0)], recursion_limit: tcx.recursion_limit(), adt_components, + exhaustive, } } + + /// Called when `ty` is found to always require drop. + /// If the exhaustive flag is true, then `Ok(ty)` is returned like any other type. + /// Otherwise, `Err(AlwaysRequireDrop)` is returned, which will cause iteration to abort. + fn always_drop_component(&self, ty: Ty<'tcx>) -> NeedsDropResult> { + if self.exhaustive { Ok(ty) } else { Err(AlwaysRequiresDrop) } + } } impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> @@ -131,19 +144,22 @@ where { type Item = NeedsDropResult>; + #[instrument(level = "debug", skip(self), ret)] fn next(&mut self) -> Option>> { let tcx = self.tcx; while let Some((ty, level)) = self.unchecked_tys.pop() { + debug!(?ty, "needs_drop_components: inspect"); if !self.recursion_limit.value_within_limit(level) { // Not having a `Span` isn't great. But there's hopefully some other // recursion limit error as well. + debug!("needs_drop_components: recursion limit exceeded"); tcx.dcx().emit_err(NeedsDropOverflow { query_ty: self.query_ty }); - return Some(Err(AlwaysRequiresDrop)); + return Some(self.always_drop_component(ty)); } let components = match needs_drop_components(tcx, ty) { - Err(e) => return Some(Err(e)), + Err(AlwaysRequiresDrop) => return Some(self.always_drop_component(ty)), Ok(components) => components, }; debug!("needs_drop_components({:?}) = {:?}", ty, components); @@ -171,7 +187,7 @@ where if self.reveal_coroutine_witnesses { queue_type(self, args.as_coroutine().witness()); } else { - return Some(Err(AlwaysRequiresDrop)); + return Some(self.always_drop_component(ty)); } } ty::CoroutineWitness(def_id, args) => { @@ -186,7 +202,7 @@ where } } - _ if component.is_copy_modulo_regions(tcx, self.typing_env) => (), + _ if component.is_copy_modulo_regions(tcx, self.typing_env) => {} ty::Closure(_, args) => { for upvar in args.as_closure().upvar_tys() { @@ -205,7 +221,9 @@ where // impl then check whether the field types need `Drop`. ty::Adt(adt_def, args) => { let tys = match (self.adt_components)(adt_def, args) { - Err(e) => return Some(Err(e)), + Err(AlwaysRequiresDrop) => { + return Some(self.always_drop_component(ty)); + } Ok(tys) => tys, }; for required_ty in tys { @@ -230,7 +248,8 @@ where } ty::Foreign(_) | ty::Dynamic(..) => { - return Some(Err(AlwaysRequiresDrop)); + debug!("needs_drop_components: foreign or dynamic"); + return Some(self.always_drop_component(ty)); } ty::Bool @@ -280,6 +299,7 @@ fn drop_tys_helper<'tcx>( typing_env: ty::TypingEnv<'tcx>, adt_has_dtor: impl Fn(ty::AdtDef<'tcx>) -> Option, only_significant: bool, + exhaustive: bool, ) -> impl Iterator>> { fn with_query_cache<'tcx>( tcx: TyCtxt<'tcx>, @@ -343,7 +363,7 @@ fn drop_tys_helper<'tcx>( .map(|v| v.into_iter()) }; - NeedsDropTypes::new(tcx, typing_env, ty, adt_components) + NeedsDropTypes::new(tcx, typing_env, ty, exhaustive, adt_components) } fn adt_consider_insignificant_dtor<'tcx>( @@ -384,6 +404,7 @@ fn adt_drop_tys<'tcx>( ty::TypingEnv::non_body_analysis(tcx, def_id), adt_has_dtor, false, + false, ) .collect::, _>>() .map(|components| tcx.mk_type_list(&components)) @@ -401,11 +422,31 @@ fn adt_significant_drop_tys( ty::TypingEnv::non_body_analysis(tcx, def_id), adt_consider_insignificant_dtor(tcx), true, + false, ) .collect::, _>>() .map(|components| tcx.mk_type_list(&components)) } +#[instrument(level = "debug", skip(tcx), ret)] +fn list_significant_drop_tys<'tcx>( + tcx: TyCtxt<'tcx>, + ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> &'tcx ty::List> { + tcx.mk_type_list( + &drop_tys_helper( + tcx, + ty.value, + ty::TypingEnv { typing_mode: ty::TypingMode::PostAnalysis, param_env: ty.param_env }, + adt_consider_insignificant_dtor(tcx), + true, + true, + ) + .filter_map(|res| res.ok()) + .collect::>(), + ) +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { needs_drop_raw, @@ -413,6 +454,7 @@ pub(crate) fn provide(providers: &mut Providers) { has_significant_drop_raw, adt_drop_tys, adt_significant_drop_tys, + list_significant_drop_tys, ..*providers }; } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index abadca71400..345c46f944a 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -233,6 +233,7 @@ fn check_statement<'tcx>( | StatementKind::PlaceMention(..) | StatementKind::Coverage(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => Ok(()), } } diff --git a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs index fde542c756f..508e7bdbf99 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs @@ -1,9 +1,10 @@ -// This test is to demonstrate that the lint is gated behind Edition and -// is triggered only for Edition 2021 and before. +// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is used +// because this is a migration lint. +// Only `cargo fix --edition 2024` shall activate this lint. //@ check-pass -//@ edition: 2024 //@ compile-flags: -Z unstable-options +//@ edition: 2024 #![deny(tail_expr_drop_order)] diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs index d61abae5187..0fabc1f085c 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.rs +++ b/tests/ui/drop/lint-tail-expr-drop-order.rs @@ -1,13 +1,26 @@ -//@ edition: 2021 - // Edition 2024 lint for change in drop order at tail expression // This lint is to capture potential change in program semantics // due to implementation of RFC 3606 +//@ edition: 2021 +//@ build-fail -#![deny(tail_expr_drop_order)] +#![deny(tail_expr_drop_order)] //~ NOTE: the lint level is defined here +#![allow(dropping_copy_types)] struct LoudDropper; impl Drop for LoudDropper { + //~^ NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor + //~| NOTE: `future` invokes this custom destructor + //~| NOTE: `_x` invokes this custom destructor + //~| NOTE: `#1` invokes this custom destructor fn drop(&mut self) { // This destructor should be considered significant because it is a custom destructor // and we will assume that the destructor can generate side effects arbitrarily so that @@ -23,30 +36,70 @@ impl LoudDropper { fn should_lint() -> i32 { let x = LoudDropper; + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 // Should lint x.get() + LoudDropper.get() - //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 } +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement -fn should_lint_closure() -> impl FnOnce() -> i32 { +fn should_not_lint_closure() -> impl FnOnce() -> i32 { let x = LoudDropper; - move || x.get() + LoudDropper.get() - //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - //~| WARN: this changes meaning in Rust 2024 + move || { + // Should not lint because ... + x.get() + LoudDropper.get() + } + // ^ closure captures like `x` are always dropped last by contract +} + +fn should_lint_in_nested_items() { + fn should_lint_me() -> i32 { + let x = LoudDropper; + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + // Should lint + x.get() + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 + } + //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement } +fn should_not_lint_params(x: LoudDropper) -> i32 { + // Should not lint because ... + x.get() + LoudDropper.get() +} +// ^ function parameters like `x` are always dropped last + fn should_not_lint() -> i32 { let x = LoudDropper; // Should not lint x.get() } -fn should_not_lint_in_nested_block() -> i32 { +fn should_lint_in_nested_block() -> i32 { let x = LoudDropper; - // Should not lint because Edition 2021 drops temporaries in blocks earlier already + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 { LoudDropper.get() } + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 } +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement fn should_not_lint_in_match_arm() -> i32 { let x = LoudDropper; @@ -56,14 +109,144 @@ fn should_not_lint_in_match_arm() -> i32 { } } -fn should_lint_in_nested_items() { - fn should_lint_me() -> i32 { +fn should_not_lint_when_consumed() -> (LoudDropper, i32) { + let x = LoudDropper; + // Should not lint because `LoudDropper` is consumed by the return value + (LoudDropper, x.get()) +} + +struct MyAdt { + a: LoudDropper, + b: LoudDropper, +} + +fn should_not_lint_when_consumed_in_ctor() -> MyAdt { + let a = LoudDropper; + // Should not lint + MyAdt { a, b: LoudDropper } +} + +fn should_not_lint_when_moved() -> i32 { + let x = LoudDropper; + drop(x); + // Should not lint because `x` is not live + LoudDropper.get() +} + +fn should_lint_into_async_body() -> i32 { + async fn f() { + async fn f() {} let x = LoudDropper; - // Should lint - x.get() + LoudDropper.get() - //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - //~| WARN: this changes meaning in Rust 2024 + f().await; + drop(x); + } + + let future = f(); + //~^ NOTE: `future` calls a custom destructor + //~| NOTE: `future` will be dropped later as of Edition 2024 + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_lint_generics() -> &'static str { + fn extract(_: &T) -> &'static str { + todo!() + } + let x = T::default(); + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + extract(&T::default()) + //~^ ERROR: relative drop order changing in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_lint_adt() -> i32 { + let x: Result = Ok(LoudDropper); + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_not_lint_insign_dtor() -> i32 { + let x = String::new(); + LoudDropper.get() +} + +fn should_lint_with_dtor_span() -> i32 { + struct LoudDropper3; + impl Drop for LoudDropper3 { + //~^ NOTE: `#1` invokes this custom destructor + fn drop(&mut self) { + println!("loud drop"); + } } + impl LoudDropper3 { + fn get(&self) -> i32 { + 0 + } + } + struct LoudDropper2; + impl Drop for LoudDropper2 { + //~^ NOTE: `x` invokes this custom destructor + fn drop(&mut self) { + println!("loud drop"); + } + } + impl LoudDropper2 { + fn get(&self) -> i32 { + 0 + } + } + + let x = LoudDropper2; + //~^ NOTE: `x` calls a custom destructor + //~| NOTE: `x` will be dropped later as of Edition 2024 + LoudDropper3.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 +} +//~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement + +fn should_lint_with_transient_drops() { + drop(( + { + LoudDropper.get() + //~^ ERROR: relative drop order changing in Rust 2024 + //~| NOTE: this value will be stored in a temporary; let us call it `#1` + //~| NOTE: up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 + //~| WARN: this changes meaning in Rust 2024 + //~| NOTE: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects + //~| NOTE: for more information, see issue #123739 + }, + { + let _x = LoudDropper; + //~^ NOTE: `_x` calls a custom destructor + //~| NOTE: `_x` will be dropped later as of Edition 2024 + }, + )); + //~^ NOTE: now the temporary value is dropped here, before the local variables in the block or statement } fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr index 6775c4ce6d1..f0da24605e6 100644 --- a/tests/ui/drop/lint-tail-expr-drop-order.stderr +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -1,42 +1,335 @@ -error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - --> $DIR/lint-tail-expr-drop-order.rs:27:15 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:42:15 | LL | let x = LoudDropper; - | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 -LL | // Should lint + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... LL | x.get() + LoudDropper.get() | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages note: the lint level is defined here --> $DIR/lint-tail-expr-drop-order.rs:7:9 | LL | #![deny(tail_expr_drop_order)] | ^^^^^^^^^^^^^^^^^^^^ -error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - --> $DIR/lint-tail-expr-drop-order.rs:34:23 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:67:19 + | +LL | let x = LoudDropper; + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | x.get() + LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:94:7 | LL | let x = LoudDropper; - | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 -LL | move || x.get() + LoudDropper.get() - | ^^^^^^^^^^^ + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | { LoudDropper.get() } + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages -error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 - --> $DIR/lint-tail-expr-drop-order.rs:63:19 +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:147:5 | -LL | let x = LoudDropper; - | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 -LL | // Should lint -LL | x.get() + LoudDropper.get() - | ^^^^^^^^^^^ +LL | let future = f(); + | ------ + | | + | `future` calls a custom destructor + | `future` will be dropped later as of Edition 2024 +... +LL | LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement | = warning: this changes meaning in Rust 2024 = note: for more information, see issue #123739 +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `future` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:164:14 + | +LL | let x = T::default(); + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | extract(&T::default()) + | ^^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:178:5 + | +LL | let x: Result = Ok(LoudDropper); + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:222:5 + | +LL | let x = LoudDropper2; + | - + | | + | `x` calls a custom destructor + | `x` will be dropped later as of Edition 2024 +... +LL | LoudDropper3.get() + | ^^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | } + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:195:5 + | +LL | / impl Drop for LoudDropper3 { +LL | | +LL | | fn drop(&mut self) { +LL | | println!("loud drop"); +LL | | } +LL | | } + | |_____^ +note: `x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:207:5 + | +LL | / impl Drop for LoudDropper2 { +LL | | +LL | | fn drop(&mut self) { +LL | | println!("loud drop"); +LL | | } +LL | | } + | |_____^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +error: relative drop order changing in Rust 2024 + --> $DIR/lint-tail-expr-drop-order.rs:235:13 + | +LL | LoudDropper.get() + | ^^^^^^^^^^^ + | | + | this value will be stored in a temporary; let us call it `#1` + | up until Edition 2021 `#1` is dropped last but will be dropped earlier in Edition 2024 +... +LL | let _x = LoudDropper; + | -- + | | + | `_x` calls a custom destructor + | `_x` will be dropped later as of Edition 2024 +... +LL | )); + | - now the temporary value is dropped here, before the local variables in the block or statement + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 +note: `#1` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ +note: `_x` invokes this custom destructor + --> $DIR/lint-tail-expr-drop-order.rs:11:1 + | +LL | / impl Drop for LoudDropper { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages -error: aborting due to 3 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/thir-print/thir-flat-const-variant.stdout b/tests/ui/thir-print/thir-flat-const-variant.stdout index 1840be7885b..5588cfdfa5c 100644 --- a/tests/ui/thir-print/thir-flat-const-variant.stdout +++ b/tests/ui/thir-print/thir-flat-const-variant.stdout @@ -11,9 +11,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0), }, Expr { @@ -25,9 +28,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:32: 12:34 (#0), }, Expr { @@ -47,9 +53,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0), }, Expr { @@ -61,9 +70,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:12:23: 12:35 (#0), }, ], @@ -84,9 +96,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0), }, Expr { @@ -98,9 +113,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:33: 13:35 (#0), }, Expr { @@ -120,9 +138,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0), }, Expr { @@ -134,9 +155,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:13:23: 13:36 (#0), }, ], @@ -157,9 +181,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0), }, Expr { @@ -171,9 +198,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:33: 14:35 (#0), }, Expr { @@ -193,9 +223,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0), }, Expr { @@ -207,9 +240,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:14:24: 14:36 (#0), }, ], @@ -230,9 +266,12 @@ Thir { fields: [], }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0), }, Expr { @@ -244,9 +283,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:34: 15:36 (#0), }, Expr { @@ -266,9 +308,12 @@ Thir { }, ), ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0), }, Expr { @@ -280,9 +325,12 @@ Thir { value: e2, }, ty: Foo, - temp_lifetime: Some( - Node(3), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(3), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:15:24: 15:37 (#0), }, ], @@ -312,9 +360,12 @@ Thir { block: b0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), }, Expr { @@ -326,9 +377,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat-const-variant.rs:18:11: 18:13 (#0), }, ], diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout index a31d08adab6..59cecfe511c 100644 --- a/tests/ui/thir-print/thir-flat.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -20,9 +20,12 @@ Thir { block: b0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat.rs:4:15: 4:17 (#0), }, Expr { @@ -34,9 +37,12 @@ Thir { value: e0, }, ty: (), - temp_lifetime: Some( - Node(2), - ), + temp_lifetime: TempLifetime { + temp_lifetime: Some( + Node(2), + ), + backwards_incompatible: None, + }, span: $DIR/thir-flat.rs:4:15: 4:17 (#0), }, ], diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 8cff7887661..a9d6985928a 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -26,7 +26,7 @@ params: [ body: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) kind: Scope { @@ -35,7 +35,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0) kind: Block { @@ -47,7 +47,7 @@ body: expr: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) kind: Scope { @@ -56,14 +56,14 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0) kind: Match { scrutinee: Expr { ty: Foo - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) kind: Scope { @@ -72,7 +72,7 @@ body: value: Expr { ty: Foo - temp_lifetime: Some(Node(26)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0) kind: VarRef { @@ -123,7 +123,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(13)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Scope { @@ -132,7 +132,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(13)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false) @@ -175,7 +175,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(19)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Scope { @@ -184,7 +184,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(19)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) kind: Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false) @@ -219,7 +219,7 @@ body: body: Expr { ty: bool - temp_lifetime: Some(Node(24)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Scope { @@ -228,7 +228,7 @@ body: value: Expr { ty: bool - temp_lifetime: Some(Node(24)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) kind: Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false) @@ -257,7 +257,7 @@ params: [ body: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) kind: Scope { @@ -266,7 +266,7 @@ body: value: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree-match.rs:23:11: 23:13 (#0) kind: Block { diff --git a/tests/ui/thir-print/thir-tree.stdout b/tests/ui/thir-print/thir-tree.stdout index ef6db368dbe..b39581ad841 100644 --- a/tests/ui/thir-print/thir-tree.stdout +++ b/tests/ui/thir-print/thir-tree.stdout @@ -4,7 +4,7 @@ params: [ body: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree.rs:4:15: 4:17 (#0) kind: Scope { @@ -13,7 +13,7 @@ body: value: Expr { ty: () - temp_lifetime: Some(Node(2)) + temp_lifetime: TempLifetime { temp_lifetime: Some(Node(2)), backwards_incompatible: None } span: $DIR/thir-tree.rs:4:15: 4:17 (#0) kind: Block { -- cgit 1.4.1-3-g733a5 From 5777c734383901b6c0ac1dc0ba04059f29cc88b1 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Fri, 18 Oct 2024 21:23:16 +0100 Subject: Stabilize const_pin_2 --- library/core/src/lib.rs | 1 - library/core/src/pin.rs | 6 ++++-- library/core/tests/lib.rs | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 3b8ac20e527..d30bf96cfd4 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -121,7 +121,6 @@ #![feature(const_float_methods)] #![feature(const_heap)] #![feature(const_nonnull_new)] -#![feature(const_pin_2)] #![feature(const_ptr_sub_ptr)] #![feature(const_raw_ptr_comparison)] #![feature(const_size_of_val)] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 254b306fcaa..c14c49a0d92 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1214,7 +1214,8 @@ impl> Pin { /// assert_eq!(*r, 5); /// ``` #[inline(always)] - #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const fn into_inner(pin: Pin) -> Ptr { pin.__pointer @@ -1503,7 +1504,8 @@ impl Pin { /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. #[inline(always)] - #[rustc_const_unstable(feature = "const_pin_2", issue = "76654")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + #[rustc_const_stable(feature = "const_pin", since = "CURRENT_RUSTC_VERSION")] #[stable(feature = "pin_into_inner", since = "1.39.0")] pub const unsafe fn into_inner_unchecked(pin: Pin) -> Ptr { pin.__pointer diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index f515e9e4109..f7825571cd7 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -21,7 +21,6 @@ #![feature(const_eval_select)] #![feature(const_heap)] #![feature(const_nonnull_new)] -#![feature(const_pin_2)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] -- cgit 1.4.1-3-g733a5 From f37d021d6ccb7949ba8e8b2a5d6e91686063da2a Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 20 Nov 2024 13:48:48 +0100 Subject: Account for `wasm32v1-none` when exporting TLS symbols --- compiler/rustc_codegen_ssa/src/back/linker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4f3664a503d..6ee599c9964 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1279,7 +1279,7 @@ impl<'a> WasmLd<'a> { let mut wasm_ld = WasmLd { cmd, sess }; if sess.target_features.contains(&sym::atomics) { wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); - if sess.target.os == "unknown" { + if sess.target.os == "unknown" || sess.target.os == "none" { wasm_ld.link_args(&[ "--export=__wasm_init_tls", "--export=__tls_size", @@ -1403,7 +1403,7 @@ impl<'a> Linker for WasmLd<'a> { // symbols explicitly passed via the `--export` flags above and hides all // others. Various bits and pieces of wasm32-unknown-unknown tooling use // this, so be sure these symbols make their way out of the linker as well. - if self.sess.target.os == "unknown" { + if self.sess.target.os == "unknown" || self.sess.target.os == "none" { self.link_args(&["--export=__heap_base", "--export=__data_end"]); } } -- cgit 1.4.1-3-g733a5 From 06e66d78c3a104b30fd59714d4dbb1a5d9f351bb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 19 Nov 2024 21:23:10 +0000 Subject: Rip out built-in PointerLike impl --- compiler/rustc_middle/src/ty/context.rs | 14 ---------- .../src/solve/assembly/mod.rs | 10 ------- .../src/solve/effect_goals.rs | 7 ----- .../src/solve/normalizes_to/mod.rs | 7 ----- .../src/solve/trait_goals.rs | 26 ------------------ .../src/traits/select/candidate_assembly.rs | 31 ---------------------- compiler/rustc_type_ir/src/interner.rs | 9 +------ compiler/rustc_type_ir/src/lang_items.rs | 1 - 8 files changed, 1 insertion(+), 104 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ad42eacf823..b4d29f08a0f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -602,19 +602,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.coroutine_is_async_gen(coroutine_def_id) } - // We don't use `TypingEnv` here as it's only defined in `rustc_middle` and - // `rustc_next_trait_solver` shouldn't have to know about it. - fn layout_is_pointer_like( - self, - typing_mode: ty::TypingMode<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> bool { - let typing_env = ty::TypingEnv { typing_mode, param_env }; - self.layout_of(self.erase_regions(typing_env).as_query_input(self.erase_regions(ty))) - .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout)) - } - type UnsizingParams = &'tcx rustc_index::bit_set::BitSet; fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams { self.unsizing_params_for_adt(adt_def_id) @@ -688,7 +675,6 @@ bidirectional_lang_item_map! { Metadata, Option, PointeeTrait, - PointerLike, Poll, Sized, TransmuteTrait, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index ebf7372926f..78344571088 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -159,13 +159,6 @@ where goal: Goal, ) -> Result, NoSolution>; - /// A type is `PointerLike` if we can compute its layout, and that layout - /// matches the layout of `usize`. - fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution>; - /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, D>, @@ -449,9 +442,6 @@ where ty::ClosureKind::FnOnce, ) } - Some(TraitSolverLangItem::PointerLike) => { - G::consider_builtin_pointer_like_candidate(self, goal) - } Some(TraitSolverLangItem::FnPtrTrait) => { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 282ca2fedbc..1f5ca71dd6f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -210,13 +210,6 @@ where Err(NoSolution) } - fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, - ) -> Result, NoSolution> { - unreachable!("PointerLike is not const") - } - fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 8a01659953d..6b407640426 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -363,13 +363,6 @@ where panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } - fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - panic!("`PointerLike` does not have an associated type: {:?}", goal); - } - fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index e64d4eed9d8..ce16258d180 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -248,32 +248,6 @@ where ) } - fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - if goal.predicate.polarity != ty::PredicatePolarity::Positive { - return Err(NoSolution); - } - - let cx = ecx.cx(); - // But if there are inference variables, we have to wait until it's resolved. - if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - - if cx.layout_is_pointer_like( - ecx.typing_mode(goal.param_env), - goal.param_env, - goal.predicate.self_ty(), - ) { - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) - .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) - } else { - Err(NoSolution) - } - } - fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, 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 1e0c487c4d4..345e1cc31f3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -111,8 +111,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::Tuple) { self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::PointerLike) { - self.assemble_candidate_for_pointer_like(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); } else { @@ -1216,35 +1214,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_candidate_for_pointer_like( - &mut self, - obligation: &PolyTraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - // The regions of a type don't affect the size of the type - let tcx = self.tcx(); - let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty()); - - // But if there are inference variables, we have to wait until it's resolved. - if (obligation.param_env, self_ty).has_non_region_infer() { - candidates.ambiguous = true; - return; - } - - // We should erase regions from both the param-env and type, since both - // may have infer regions. Specifically, after canonicalizing and instantiating, - // early bound regions turn into region vars in both the new and old solver. - let key = self.infcx.pseudo_canonicalize_query( - tcx.erase_regions(obligation.param_env), - tcx.erase_regions(self_ty), - ); - if let Ok(layout) = tcx.layout_of(key) - && layout.layout.is_pointer_like(&tcx.data_layout) - { - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } - } - fn assemble_candidates_for_fn_ptr_trait( &mut self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6e6cf91d855..4e1715dbd0f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -13,7 +13,7 @@ use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; -use crate::{self as ty, TypingMode, search_graph}; +use crate::{self as ty, search_graph}; pub trait Interner: Sized @@ -278,13 +278,6 @@ pub trait Interner: fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool; fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool; - fn layout_is_pointer_like( - self, - typing_mode: TypingMode, - param_env: Self::ParamEnv, - ty: Self::Ty, - ) -> bool; - type UnsizingParams: Deref>; fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index d6ca22a90a4..df43346065d 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -31,7 +31,6 @@ pub enum TraitSolverLangItem { Metadata, Option, PointeeTrait, - PointerLike, Poll, Sized, TransmuteTrait, -- cgit 1.4.1-3-g733a5 From 228068bc6efb16f359b5318e66fa789c2f58ce60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Nov 2024 02:46:56 +0000 Subject: Make PointerLike opt-in as a trait --- .../rustc_hir_analysis/src/coherence/builtin.rs | 85 ++++++++++++++++++---- library/alloc/src/boxed.rs | 6 ++ library/alloc/src/lib.rs | 1 + library/core/src/marker.rs | 12 +++ tests/crashes/113280.rs | 16 ---- tests/crashes/127676.rs | 8 -- tests/ui/dyn-star/async-block-dyn-star.rs | 9 +++ tests/ui/dyn-star/async-block-dyn-star.stderr | 20 +++++ ...eck-size-at-cast-polymorphic-bad.current.stderr | 11 ++- .../check-size-at-cast-polymorphic-bad.next.stderr | 11 ++- tests/ui/dyn-star/drop.rs | 7 +- tests/ui/dyn-star/enum-cast.rs | 7 +- tests/ui/dyn-star/error.rs | 2 +- tests/ui/dyn-star/error.stderr | 4 +- tests/ui/dyn-star/float-as-dyn-star.rs | 16 ++++ tests/ui/dyn-star/float-as-dyn-star.stderr | 21 ++++++ tests/ui/dyn-star/upcast.stderr | 10 ++- 17 files changed, 194 insertions(+), 52 deletions(-) delete mode 100644 tests/crashes/113280.rs delete mode 100644 tests/crashes/127676.rs create mode 100644 tests/ui/dyn-star/async-block-dyn-star.rs create mode 100644 tests/ui/dyn-star/async-block-dyn-star.stderr create mode 100644 tests/ui/dyn-star/float-as-dyn-star.rs create mode 100644 tests/ui/dyn-star/float-as-dyn-star.stderr diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index c2ad61820a7..3b49bc41ffe 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>( ) -> Result<(), ErrorGuaranteed> { let lang_items = tcx.lang_items(); let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; - let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); - res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); - res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| { + checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?; + checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?; + checker.check(lang_items.const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) - })); - res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { + })?; + checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy) - })); - - res = res.and( - checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized), - ); - res.and( - checker - .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn), - ) + })?; + checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?; + checker + .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; + checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?; + Ok(()) } struct Checker<'tcx> { @@ -663,3 +660,63 @@ fn infringing_fields_error<'tcx>( err.emit() } + +fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { + let tcx = checker.tcx; + let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id); + let impl_span = tcx.def_span(checker.impl_def_id); + let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); + + // If an ADT is repr(transparent)... + if let ty::Adt(def, args) = *self_ty.kind() + && def.repr().transparent() + { + // FIXME(compiler-errors): This should and could be deduplicated into a query. + // Find the nontrivial field. + let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did()); + let nontrivial_field = def.all_fields().find(|field_def| { + let field_ty = tcx.type_of(field_def.did).instantiate_identity(); + !tcx.layout_of(adt_typing_env.as_query_input(field_ty)) + .is_ok_and(|layout| layout.layout.is_1zst()) + }); + + if let Some(nontrivial_field) = nontrivial_field { + // Check that the nontrivial field implements `PointerLike`. + let nontrivial_field = nontrivial_field.ty(tcx, args); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound( + ObligationCause::misc(impl_span, checker.impl_def_id), + param_env, + nontrivial_field, + tcx.lang_items().pointer_like().unwrap(), + ); + // FIXME(dyn-star): We should regionck this implementation. + if ocx.select_all_or_error().is_empty() { + return Ok(()); + } + } + } + + let is_permitted_primitive = match *self_ty.kind() { + ty::Adt(def, _) => def.is_box(), + ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true, + _ => false, + }; + + if is_permitted_primitive + && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty)) + && layout.layout.is_pointer_like(&tcx.data_layout) + { + return Ok(()); + } + + Err(tcx + .dcx() + .struct_span_err( + impl_span, + "implementation must be applied to type that has the same ABI as a pointer, \ + or is `repr(transparent)` and whose field is `PointerLike`", + ) + .emit()) +} diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ac3e4626ee5..ee60ec0fbac 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -191,6 +191,8 @@ use core::error::{self, Error}; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; +#[cfg(not(bootstrap))] +use core::marker::PointerLike; use core::marker::{Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ @@ -2131,3 +2133,7 @@ impl Error for Box { Error::provide(&**self, request); } } + +#[cfg(not(bootstrap))] +#[unstable(feature = "pointer_like_trait", issue = "none")] +impl PointerLike for Box {} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7839fe04b8d..041ff37897f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -136,6 +136,7 @@ #![feature(panic_internals)] #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] +#![feature(pointer_like_trait)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1c5c58d64a2..c8ea52a1fb0 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -981,6 +981,18 @@ pub trait Tuple {} )] pub trait PointerLike {} +#[cfg(not(bootstrap))] +marker_impls! { + #[unstable(feature = "pointer_like_trait", issue = "none")] + PointerLike for + usize, + {T} &T, + {T} &mut T, + {T} *const T, + {T} *mut T, + {T: PointerLike} crate::pin::Pin, +} + /// A marker for types which can be used as types of `const` generic parameters. /// /// These types must have a proper equivalence relation (`Eq`) and it must be automatically diff --git a/tests/crashes/113280.rs b/tests/crashes/113280.rs deleted file mode 100644 index 86677f416fe..00000000000 --- a/tests/crashes/113280.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #113280 -//@ only-x86_64 - -#![feature(dyn_star, pointer_like_trait)] -#![allow(incomplete_features)] - -use std::fmt::Debug; -use std::marker::PointerLike; - -fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a { - f32::from_bits(0x1) as f64 -} - -fn main() { - println!("{:?}", make_dyn_star(Box::new(1i32))); -} diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs deleted file mode 100644 index 81149c2ef84..00000000000 --- a/tests/crashes/127676.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #127676 -//@ edition:2018 - -#![feature(dyn_star,const_async_blocks)] - -static S: dyn* Send + Sync = async { 42 }; - -pub fn main() {} diff --git a/tests/ui/dyn-star/async-block-dyn-star.rs b/tests/ui/dyn-star/async-block-dyn-star.rs new file mode 100644 index 00000000000..9bffd6c6725 --- /dev/null +++ b/tests/ui/dyn-star/async-block-dyn-star.rs @@ -0,0 +1,9 @@ +//@ edition:2018 + +#![feature(dyn_star, const_async_blocks)] +//~^ WARN the feature `dyn_star` is incomplete + +static S: dyn* Send + Sync = async { 42 }; +//~^ needs to have the same ABI as a pointer + +pub fn main() {} diff --git a/tests/ui/dyn-star/async-block-dyn-star.stderr b/tests/ui/dyn-star/async-block-dyn-star.stderr new file mode 100644 index 00000000000..f62c85c0ad2 --- /dev/null +++ b/tests/ui/dyn-star/async-block-dyn-star.stderr @@ -0,0 +1,20 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/async-block-dyn-star.rs:3:12 + | +LL | #![feature(dyn_star, const_async_blocks)] + | ^^^^^^^^ + | + = note: see issue #102425 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer + --> $DIR/async-block-dyn-star.rs:6:30 + | +LL | static S: dyn* Send + Sync = async { 42 }; + | ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr index 7b5ea7bb707..a0aff69f396 100644 --- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr +++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr @@ -1,14 +1,17 @@ error[E0277]: `&T` needs to have the same ABI as a pointer --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 | +LL | fn polymorphic(t: &T) { + | - this type parameter needs to be `Sized` LL | dyn_debug(t); | ^ `&T` needs to be a pointer-like type | - = help: the trait `PointerLike` is not implemented for `&T` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + = note: required for `&T` to implement `PointerLike` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn polymorphic(t: &T) { +LL + fn polymorphic(t: &T) { | -LL | fn polymorphic(t: &T) where &T: PointerLike { - | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr index 7b5ea7bb707..a0aff69f396 100644 --- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr +++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr @@ -1,14 +1,17 @@ error[E0277]: `&T` needs to have the same ABI as a pointer --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 | +LL | fn polymorphic(t: &T) { + | - this type parameter needs to be `Sized` LL | dyn_debug(t); | ^ `&T` needs to be a pointer-like type | - = help: the trait `PointerLike` is not implemented for `&T` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + = note: required for `&T` to implement `PointerLike` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn polymorphic(t: &T) { +LL + fn polymorphic(t: &T) { | -LL | fn polymorphic(t: &T) where &T: PointerLike { - | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/dyn-star/drop.rs b/tests/ui/dyn-star/drop.rs index ca86f1b5b01..bc746331527 100644 --- a/tests/ui/dyn-star/drop.rs +++ b/tests/ui/dyn-star/drop.rs @@ -1,13 +1,18 @@ //@ run-pass //@ check-run-results -#![feature(dyn_star)] +#![feature(dyn_star, pointer_like_trait)] #![allow(incomplete_features)] use std::fmt::Debug; +use std::marker::PointerLike; #[derive(Debug)] +#[repr(transparent)] struct Foo(#[allow(dead_code)] usize); +// FIXME(dyn_star): Make this into a derive. +impl PointerLike for Foo {} + impl Drop for Foo { fn drop(&mut self) { println!("destructor called"); diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs index 6e895e9527a..3cc7390eb12 100644 --- a/tests/ui/dyn-star/enum-cast.rs +++ b/tests/ui/dyn-star/enum-cast.rs @@ -3,13 +3,18 @@ // This used to ICE, because the compiler confused a pointer-like to dyn* coercion // with a c-like enum to integer cast. -#![feature(dyn_star)] +#![feature(dyn_star, pointer_like_trait)] #![expect(incomplete_features)] +use std::marker::PointerLike; + +#[repr(transparent)] enum E { Num(usize), } +impl PointerLike for E {} + trait Trait {} impl Trait for E {} diff --git a/tests/ui/dyn-star/error.rs b/tests/ui/dyn-star/error.rs index d8261387efa..7288596f3fa 100644 --- a/tests/ui/dyn-star/error.rs +++ b/tests/ui/dyn-star/error.rs @@ -7,7 +7,7 @@ trait Foo {} fn make_dyn_star() { let i = 42; - let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied + let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied } fn main() {} diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr index a9f4a054519..55981c03bac 100644 --- a/tests/ui/dyn-star/error.stderr +++ b/tests/ui/dyn-star/error.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `{integer}: Foo` is not satisfied +error[E0277]: the trait bound `usize: Foo` is not satisfied --> $DIR/error.rs:10:27 | LL | let dyn_i: dyn* Foo = i; - | ^ the trait `Foo` is not implemented for `{integer}` + | ^ the trait `Foo` is not implemented for `usize` | help: this trait has no implementations, consider adding one --> $DIR/error.rs:6:1 diff --git a/tests/ui/dyn-star/float-as-dyn-star.rs b/tests/ui/dyn-star/float-as-dyn-star.rs new file mode 100644 index 00000000000..1b629c64c25 --- /dev/null +++ b/tests/ui/dyn-star/float-as-dyn-star.rs @@ -0,0 +1,16 @@ +//@ only-x86_64 + +#![feature(dyn_star, pointer_like_trait)] +//~^ WARN the feature `dyn_star` is incomplete + +use std::fmt::Debug; +use std::marker::PointerLike; + +fn make_dyn_star() -> dyn* Debug + 'static { + f32::from_bits(0x1) as f64 + //~^ ERROR `f64` needs to have the same ABI as a pointer +} + +fn main() { + println!("{:?}", make_dyn_star()); +} diff --git a/tests/ui/dyn-star/float-as-dyn-star.stderr b/tests/ui/dyn-star/float-as-dyn-star.stderr new file mode 100644 index 00000000000..9caba512e5f --- /dev/null +++ b/tests/ui/dyn-star/float-as-dyn-star.stderr @@ -0,0 +1,21 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/float-as-dyn-star.rs:3:12 + | +LL | #![feature(dyn_star, pointer_like_trait)] + | ^^^^^^^^ + | + = note: see issue #102425 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `f64` needs to have the same ABI as a pointer + --> $DIR/float-as-dyn-star.rs:10:5 + | +LL | f32::from_bits(0x1) as f64 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `f64` + = help: the trait `PointerLike` is implemented for `usize` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr index adef9525bf1..801e1c233c1 100644 --- a/tests/ui/dyn-star/upcast.stderr +++ b/tests/ui/dyn-star/upcast.stderr @@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)] = note: see issue #102425 for more information = note: `#[warn(incomplete_features)]` on by default +error[E0277]: `W` needs to have the same ABI as a pointer + --> $DIR/upcast.rs:28:23 + | +LL | let w: dyn* Foo = W(0); + | ^^^^ `W` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `W` + error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer --> $DIR/upcast.rs:30:23 | @@ -15,6 +23,6 @@ LL | let w: dyn* Bar = w; | = help: the trait `PointerLike` is not implemented for `dyn* Foo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From 186e282a43f384d456579ab50c5d6a48fd5cca1b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Nov 2024 18:11:37 +0100 Subject: Add `UnordMap::clear` method --- compiler/rustc_data_structures/src/unord.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index bafb16a8b5e..34895d3efe6 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -602,6 +602,11 @@ impl UnordMap { .into_iter() .map(|(_, v)| v) } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } } impl Index<&Q> for UnordMap -- cgit 1.4.1-3-g733a5 From 09ef8ece2882df74e4d132d443a2ec37620d5eb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Nov 2024 07:45:20 +0100 Subject: 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 1fcd33752ec..effed0cd180 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -875df370be806c837f58abb638329905e969ace4 +2d0ea7956c45de6e421fd579e2ded27be405dec6 -- cgit 1.4.1-3-g733a5 From ec6fe118d9f11c236288a589113db887cade703c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Nov 2024 07:59:07 +0100 Subject: fmt --- src/tools/miri/src/eval.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 1d074b09bd3..1df1d08802a 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -270,12 +270,8 @@ pub fn create_ecx<'tcx>( ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> { let typing_env = ty::TypingEnv::fully_monomorphized(); let layout_cx = LayoutCx::new(tcx, typing_env); - let mut ecx = InterpCx::new( - tcx, - rustc_span::DUMMY_SP, - typing_env, - MiriMachine::new(config, layout_cx), - ); + let mut ecx = + InterpCx::new(tcx, rustc_span::DUMMY_SP, typing_env, MiriMachine::new(config, layout_cx)); // Some parts of initialization require a full `InterpCx`. MiriMachine::late_init(&mut ecx, config, { -- cgit 1.4.1-3-g733a5