From ba96988b467a8e4aa220068a311573407bf444d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Oct 2026 08:09:13 +0200 Subject: [PATCH 01/18] add some comments to Windows remove_dir_all --- library/std/src/sys/fs/windows.rs | 4 ++-- library/std/src/sys/fs/windows/remove_dir_all.rs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index c4e0bb6ecf51f..a47ba3293f4f7 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -952,8 +952,8 @@ impl<'a> Iterator for DirBuffIter<'a> { // While this is guaranteed to be aligned in documentation for // https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info // it does not seem that reality is so kind, and assuming this - // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530) - // presumably, this can be blamed on buggy filesystem drivers, but who knows. + // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530). + // Presumably, this can be blamed on buggy filesystem drivers, but who knows. let next_entry = (&raw const (*info).NextEntryOffset).read_unaligned() as usize; let length = (&raw const (*info).FileNameLength).read_unaligned() as usize; let attrs = (&raw const (*info).FileAttributes).read_unaligned(); diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index 8f89dbf1be16d..c96de67f50ab7 100644 --- a/library/std/src/sys/fs/windows/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -181,6 +181,10 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { let name = unicode_str!(&name); if is_directory { let Some(subdir) = open_dir(&dir, name)? else { continue }; + // Continue with new subdirectory. `restart` does not matter since it's a new + // directory handle anyway. We skip the remaining elements in `buffer`. When the + // subdirectory is done, we will restart iterating `dir`, so we will see those + // elements again. dirlist.push(dir); dirlist.push(subdir); continue 'outer; @@ -192,6 +196,7 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { } } if more_data { + // Continue outer loop with this directory. dirlist.push(dir); restart = false; } else { @@ -199,6 +204,7 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { // need to wait some time for files to be removed from the filesystem. let name = unicode_str!(""); retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?; + // We are done with a subdirectory. Continue by restarting in the parent directory. restart = true; } } From e90fd2c67712ed54a40f80d3813bcf0400102b20 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Oct 2026 12:01:41 +0200 Subject: [PATCH 02/18] avoid re-reading the same dir entries over and over --- library/std/src/sys/fs/windows.rs | 3 ++ .../std/src/sys/fs/windows/remove_dir_all.rs | 46 ++++++++++--------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index a47ba3293f4f7..9b04770ac687f 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -862,6 +862,7 @@ impl File { /// `restart` is set to `true`. /// /// The returned bool indicates if there are more entries or not. + /// You must only iterate the buffer if this returned `true`! /// It is an error if `self` is not a directory. /// /// # Symlinks and other reparse points @@ -883,6 +884,8 @@ impl File { buffer.capacity() as _, ); if result == 0 { + // Apparently ERROR_NO_MORE_FILES also means that the buffer is empty / was left + // unchanged. FIXME: find docs that say this. let err = api::get_last_error(); if err.code == c::ERROR_NO_MORE_FILES { Ok(false) } else { Err(err) } } else { diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index c96de67f50ab7..f701a22f7d6dd 100644 --- a/library/std/src/sys/fs/windows/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -174,39 +174,41 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { let mut buffer = DirBuff::new(); let mut dirlist = vec![dir]; - let mut restart = true; - 'outer: while let Some(dir) = dirlist.pop() { + while let Some(dir) = dirlist.pop() { + let restart = false; // we never have to restart, we iterate every directory only once let more_data = dir.fill_dir_buff(&mut buffer, restart)?; + if !more_data { + // This directory is done! + // Attempt to delete, retrying on not empty errors because we may + // need to wait some time for files to be removed from the filesystem. + let name = unicode_str!(""); + retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?; + continue; + } + + // There is more data, so we have to re-insert `dir` so it gets visited again. We need to + // push it first so that it gets visited after any subdirs that we push below. We also need + // to still access it during the `for` loop so remember where we put it. + let dir_idx = dirlist.len(); + dirlist.push(dir); + // To avoid indexing `dirlist` each time through the loop, we use a reference that we + // re-compute whenever the borrow got invalidated. + let mut dir = &dirlist[dir_idx]; + for (name, is_directory) in buffer.iter() { let name = unicode_str!(&name); if is_directory { - let Some(subdir) = open_dir(&dir, name)? else { continue }; - // Continue with new subdirectory. `restart` does not matter since it's a new - // directory handle anyway. We skip the remaining elements in `buffer`. When the - // subdirectory is done, we will restart iterating `dir`, so we will see those - // elements again. - dirlist.push(dir); + let Some(subdir) = open_dir(dir, name)? else { continue }; dirlist.push(subdir); - continue 'outer; + // We need to re-create the borrow. + dir = &dirlist[dir_idx] } else { // Attempt to delete, retrying on sharing violation errors as these // can often be very temporary. E.g. if something takes just a // bit longer than expected to release a file handle. - retry(|| delete(&dir, name), WinError::SHARING_VIOLATION)?; + retry(|| delete(dir, name), WinError::SHARING_VIOLATION)?; } } - if more_data { - // Continue outer loop with this directory. - dirlist.push(dir); - restart = false; - } else { - // Attempt to delete, retrying on not empty errors because we may - // need to wait some time for files to be removed from the filesystem. - let name = unicode_str!(""); - retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?; - // We are done with a subdirectory. Continue by restarting in the parent directory. - restart = true; - } } Ok(()) } From dff7a207bbbe116945d81ac05a3f0f15a48755bf Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 8 Oct 2026 13:10:12 +0200 Subject: [PATCH 03/18] std: use `SOCK_NONBLOCK` in `connect_timeout` --- .../src/sys/net/connection/socket/hermit.rs | 16 +--- .../std/src/sys/net/connection/socket/mod.rs | 37 ++++++++- .../src/sys/net/connection/socket/solid.rs | 13 +--- .../std/src/sys/net/connection/socket/unix.rs | 16 +--- .../src/sys/net/connection/socket/windows.rs | 78 ++++++++----------- 5 files changed, 72 insertions(+), 88 deletions(-) diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index f43395ce8fd80..f2dbea7176ae1 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -51,21 +51,7 @@ impl Socket { Ok(()) } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addr, len) = socket_addr_to_c(addr); - cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(netc::errno::EINPROGRESS) => {} - Err(e) => return Err(e), - } - + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 55db60fde694d..bb2bd4a76a608 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -57,6 +57,21 @@ const MAX_SEND_LEN: usize = _ => libc::ssize_t::MAX as usize, }; +/// Some systems support setting the nonblocking mode upon socket creation, which +/// saves a syscall. +const SOCK_NONBLOCK: i32 = cfg_select! { + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "hermit", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ) => c::SOCK_NONBLOCK, + _ => 0, +}; + cfg_select! { any( target_os = "dragonfly", @@ -407,8 +422,26 @@ impl TcpStream { pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { init(); - let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?; - sock.connect_timeout(addr, timeout)?; + let sock = Socket::new(addr_family(addr), c::SOCK_STREAM | SOCK_NONBLOCK)?; + if SOCK_NONBLOCK == 0 { + // The `SOCK_NONBLOCK` option is unsupported... + sock.set_nonblocking(true)?; + } + + match sock.connect(addr) { + Ok(()) => { + sock.set_nonblocking(false)?; + return Ok(TcpStream { inner: sock }); + } + #[cfg(not(target_os = "windows"))] + Err(ref e) if e.raw_os_error() == Some(c::EINPROGRESS) => {} + #[cfg(target_os = "windows")] + Err(ref e) if e.raw_os_error() == Some(crate::sys::pal::c::WSAEWOULDBLOCK) => {} + Err(e) => return Err(e), + } + + sock.set_nonblocking(false)?; + sock.poll_connected(timeout)?; Ok(TcpStream { inner: sock }) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 9fe08ec951e75..ccb2c218b95c6 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -126,18 +126,7 @@ impl Socket { Ok(()) } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = self.connect(addr); - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS - Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { return Err(io::Error::ZERO_TIMEOUT); } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 15e9dc2c7cc9d..a240850ec087e 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -171,21 +171,7 @@ impl Socket { } } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addr, len) = socket_addr_to_c(addr); - cvt(libc::connect(self.as_raw_fd(), addr.as_ptr(), len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index e9d5336001fd8..14e5d0c12d2e3 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -158,57 +158,47 @@ impl Socket { cvt(result).map(drop) } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let result = self.connect(addr); - self.set_nonblocking(false)?; + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::ZERO_TIMEOUT); + } - match result { - Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => { - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::ZERO_TIMEOUT); - } + let mut timeout = c::TIMEVAL { + tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, + tv_usec: timeout.subsec_micros() as c_long, + }; - let mut timeout = c::TIMEVAL { - tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, - tv_usec: timeout.subsec_micros() as c_long, - }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } + let fds = { + let mut fds = unsafe { mem::zeroed::() }; + fds.fd_count = 1; + fds.fd_array[0] = self.as_raw(); + fds + }; + + let mut writefds = fds; + let mut errorfds = fds; + + let count = { + let result = + unsafe { c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) }; + cvt(result)? + }; - let fds = { - let mut fds = unsafe { mem::zeroed::() }; - fds.fd_count = 1; - fds.fd_array[0] = self.as_raw(); - fds - }; - - let mut writefds = fds; - let mut errorfds = fds; - - let count = { - let result = unsafe { - c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) - }; - cvt(result)? - }; - - match count { - 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), - _ => { - if writefds.fd_count != 1 { - if let Some(e) = self.take_error()? { - return Err(e); - } - } - - Ok(()) + match count { + 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), + _ => { + if writefds.fd_count != 1 { + if let Some(e) = self.take_error()? { + return Err(e); } } + + Ok(()) } - _ => result, } } From 2cf85324606683909e1c3dab5731b1b6f9bf8447 Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Wed, 14 Oct 2026 11:10:16 +0100 Subject: [PATCH 04/18] Rename `PostTypeckUntilBorrowck` -> `PostTypeckThroughBorrowck` --- compiler/rustc_borrowck/src/implied_bounds.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- .../src/region_infer/opaque_types/mod.rs | 10 +++---- .../src/check_consts/qualifs.rs | 2 +- .../src/const_eval/eval_queries.rs | 2 +- compiler/rustc_const_eval/src/lib.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 4 +-- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 2 +- compiler/rustc_hir_typeck/src/opaque_types.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 10 +++---- .../rustc_infer/src/infer/opaque_types/mod.rs | 2 +- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 4 +-- compiler/rustc_middle/src/ty/mod.rs | 12 ++++---- compiler/rustc_mir_build/src/builder/mod.rs | 4 +-- compiler/rustc_mir_build/src/builder/scope.rs | 2 +- .../rustc_mir_build/src/check_tail_calls.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 +- .../src/thir/pattern/check_match.rs | 2 +- .../rustc_mir_transform/src/elaborate_drop.rs | 2 +- .../src/solve/assembly/mod.rs | 4 +-- .../src/solve/eval_ctxt/mod.rs | 8 ++--- .../src/solve/normalizes_to.rs | 2 +- .../src/solve/project_goals/opaque_types.rs | 4 +-- .../src/solve/trait_goals.rs | 4 +-- compiler/rustc_session/src/options.rs | 4 +-- .../src/solve/delegate.rs | 2 +- .../src/solve/fulfill.rs | 2 +- .../src/traits/fulfill.rs | 2 +- .../src/traits/implied_outlives_bounds.rs | 2 +- .../src/traits/normalize.rs | 4 +-- .../src/traits/project.rs | 2 +- .../src/traits/query/normalize.rs | 2 +- .../src/traits/select/mod.rs | 6 ++-- compiler/rustc_ty_utils/src/instance.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 4 +-- compiler/rustc_type_ir/src/infer_ctxt.rs | 30 +++++++++---------- .../rustc_type_ir/src/region_constraint.rs | 2 +- compiler/rustc_type_ir/src/relate/combine.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 2 +- 42 files changed, 83 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_borrowck/src/implied_bounds.rs b/compiler/rustc_borrowck/src/implied_bounds.rs index d5f765edfdb5d..f787e011944f2 100644 --- a/compiler/rustc_borrowck/src/implied_bounds.rs +++ b/compiler/rustc_borrowck/src/implied_bounds.rs @@ -40,7 +40,7 @@ pub(super) fn mir_borrowck_implied_outlives_bounds<'tcx>( // parent body, so for these we do want to define opaque types. Not doing so can result // in incorrect errors when normalizing implied bounds. let typing_env = if tcx.is_typeck_child(body_def_id.to_def_id()) { - TypingEnv::post_typeck_until_borrowck(tcx, body_def_id) + TypingEnv::post_typeck_through_borrowck(tcx, body_def_id) } else { TypingEnv::non_body_analysis(tcx, body_def_id) }; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 96fc9b2e37651..7e1ba1fad72c4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -657,7 +657,7 @@ pub(crate) struct BorrowckInferCtxt<'tcx> { impl<'tcx> BorrowckInferCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, root_def_id: LocalDefId) -> Self { - let typing_mode = if tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_mode = if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingMode::borrowck(tcx, def_id) } else { TypingMode::analysis_in_body(tcx, def_id) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index e3240c2add95c..7892e6ed72f96 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -261,8 +261,8 @@ fn collect_defining_uses<'tcx>( DefiningScopeKind::MirBorrowck, ) { // A non-defining use. This is a hard error on stable and gets ignored - // with `TypingMode::PostTypeckUntilBorrowck`. - if infcx.tcx.use_typing_mode_post_typeck_until_borrowck() { + // with `TypingMode::PostTypeckThroughBorrowck`. + if infcx.tcx.use_typing_mode_post_typeck_through_borrowck() { match err { NonDefiningUseReason::Tainted(guar) => add_hidden_type( infcx.tcx, @@ -327,7 +327,7 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>( // If we're using the next solver, the unconstrained region may be resolved by a // fully defining use from another body. // So we don't generate error eagerly here. - if rcx.infcx.tcx.use_typing_mode_post_typeck_until_borrowck() { + if rcx.infcx.tcx.use_typing_mode_post_typeck_through_borrowck() { unconstrained_hidden_type_errors.push(UnexpectedHiddenRegion { def_id, hidden_type, @@ -362,7 +362,7 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>( DefinitionSiteHiddenType::new_error(tcx, guar) }); - if !rcx.infcx.tcx.use_typing_mode_post_typeck_until_borrowck() { + if !rcx.infcx.tcx.use_typing_mode_post_typeck_through_borrowck() { // Sometimes, when the hidden type is an inference variable, it can happen that // the hidden type becomes the opaque type itself. In this case, this was an opaque // usage of the opaque type and we can ignore it. This check is mirrored in typeck's @@ -539,7 +539,7 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>( let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { let Some(expected) = hidden_types.get(&key.def_id) else { - if !tcx.use_typing_mode_post_typeck_until_borrowck() { + if !tcx.use_typing_mode_post_typeck_through_borrowck() { if let &ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = hidden_type.ty.kind() && def_id == key.def_id.to_def_id() diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 00874bdd64097..3d1d0a12a6242 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -110,7 +110,7 @@ impl Qualif for HasMutInterior { let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, cx.body.span); let did = cx.body.source.def_id().expect_local(); - let typing_env = if cx.tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_env = if cx.tcx.use_typing_mode_post_typeck_through_borrowck() { cx.typing_env } else { ty::TypingEnv::new(cx.typing_env.param_env, TypingMode::analysis_in_body(cx.tcx, did)) 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 6ad79541bdbea..20e4c1c6085be 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -42,7 +42,7 @@ fn retry_codegen_mode_with_postanalysis<'tcx, K: TypeVisitable>, V> } ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::PostAnalysis => {} diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 981813f13c97f..091f0f71cc50d 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -34,7 +34,7 @@ fn assert_typing_mode(typing_mode: ty::TypingMode<'_>) { ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } | ty::TypingMode::Reflection - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } => bug!( "Const eval should always happens in PostAnalysis or Codegen mode. See the comment on `assert_typing_mode` for more details." ), diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0a7686a2876bb..4f753f02ed9fd 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2355,7 +2355,7 @@ pub(super) fn check_coroutine_obligations( } } else { // We're not checking region constraints here, so we can simply drop the - // added opaque type uses in `TypingMode::PostTypeckUntilBorrowck`. + // added opaque type uses in `TypingMode::PostTypeckThroughBorrowck`. let _ = infcx.take_opaque_types(); } @@ -2372,7 +2372,7 @@ pub(super) fn check_potentially_region_dependent_goals<'tcx>( let typeck_results = tcx.typeck(def_id); let param_env = tcx.param_env(def_id); - // We use `TypingMode::PostTypeckUntilBorrowck` as we want to use the opaque types computed by HIR typeck. + // We use `TypingMode::PostTypeckThroughBorrowck` as we want to use the opaque types computed by HIR typeck. let typing_mode = TypingMode::borrowck(tcx, def_id); let infcx = tcx.infer_ctxt().ignoring_regions().build(typing_mode); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9e3e3d810345e..4d76887698ad9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -719,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::TypingMode::Coherence | ty::TypingMode::Reflection - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => { diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index da9162629ec80..6d1e1bc67f8e7 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -104,7 +104,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } ty::TypingMode::Coherence | ty::TypingMode::Reflection - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 76234c7459f84..d3ed447e5201f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -360,10 +360,10 @@ impl<'tcx> Drop for InferCtxt<'tcx> { let mut inner = self.inner.borrow_mut(); let opaque_type_storage = &mut inner.opaque_type_storage; - // No need for the drop bomb when we're in `TypingMode::PostTypeckUntilBorrowck`, and the `InferCtxt` + // No need for the drop bomb when we're in `TypingMode::PostTypeckThroughBorrowck`, and the `InferCtxt` // doesn't consider regions. This is okay since after typeck, the only reason we care about opaques is // in relation to regions. In some places *after* typeck that aren't borrowck, we use - // `TypingMode::PostTypeckUntilBorrowck` to prevent defining opaque types and we simply don't care about regions. + // `TypingMode::PostTypeckThroughBorrowck` to prevent defining opaque types and we simply don't care about regions. match self.typing_mode_raw() { TypingMode::Coherence | TypingMode::Typeck { .. } @@ -373,7 +373,7 @@ impl<'tcx> Drop for InferCtxt<'tcx> { | TypingMode::Codegen => {} // In erased mode, the opaque type storage is always empty TypingMode::ErasedNotCoherence(..) => {} - TypingMode::PostTypeckUntilBorrowck { .. } => { + TypingMode::PostTypeckThroughBorrowck { .. } => { if !self.considering_regions { return; } @@ -1193,7 +1193,7 @@ impl<'tcx> InferCtxt<'tcx> { debug_assert!(!self.next_trait_solver()); match self.typing_mode_raw().assert_not_erased() { TypingMode::Typeck { defining_opaque_types_and_generators: defining_opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) } // FIXME(#132279): This function is quite weird in post-analysis @@ -1683,7 +1683,7 @@ impl<'tcx> InferCtxt<'tcx> { // errors and fail to reveal opaques while inside of bodies. We should rename this // function and require explicit comments on all use-sites in the future. ty::TypingMode::Typeck { defining_opaque_types_and_generators: _ } - | ty::TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } => { + | ty::TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } => { TypingMode::non_body_analysis() } mode @ (ty::TypingMode::Coherence diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 3cca843157b8f..6a922f75dbe9b 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -253,7 +253,7 @@ impl<'tcx> InferCtxt<'tcx> { ); } } - ty::TypingMode::PostTypeckUntilBorrowck { .. } => { + ty::TypingMode::PostTypeckThroughBorrowck { .. } => { let prev = self .inner .borrow_mut() diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0bcb42af7469d..7d130ffa462d8 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -627,7 +627,7 @@ impl<'tcx> LateContext<'tcx> { /// building a new `InferCtxt`. pub fn typing_mode(&self) -> TypingMode<'tcx> { if let Some(body_id) = self.enclosing_body - && self.tcx.use_typing_mode_post_typeck_until_borrowck() + && self.tcx.use_typing_mode_post_typeck_through_borrowck() { let def_id = self.tcx.hir_enclosing_body_owner(body_id.hir_id); TypingMode::post_borrowck_analysis(self.tcx, def_id) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 29ca694b6431b..84d5fe3fe431e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -413,7 +413,7 @@ impl<'tcx> Body<'tcx> { } pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> { - if tcx.use_typing_mode_post_typeck_until_borrowck() { + if tcx.use_typing_mode_post_typeck_through_borrowck() { match self.phase { MirPhase::Built | MirPhase::Analysis(AnalysisPhase::Initial) if let Some(def_id) = self.source.def_id().as_local() => diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 913f56eba36f5..f338dbef3c077 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2855,9 +2855,9 @@ impl<'tcx> TyCtxt<'tcx> { } #[allow(rustc::bad_opt_access)] - pub fn use_typing_mode_post_typeck_until_borrowck(self) -> bool { + pub fn use_typing_mode_post_typeck_through_borrowck(self) -> bool { self.next_trait_solver_globally() - || self.sess.opts.unstable_opts.typing_mode_post_typeck_until_borrowck + || self.sess.opts.unstable_opts.typing_mode_post_typeck_through_borrowck } pub fn assumptions_on_binders(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a4d22ea9923f2..2fe1b98402391 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1156,20 +1156,20 @@ impl<'tcx> TypingEnv<'tcx> { /// The `TypingEnv` which should be for everything happens after HIR typeck /// up-to and including borrowck itself. - pub fn post_typeck_until_borrowck(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> TypingEnv<'tcx> { + pub fn post_typeck_through_borrowck(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> TypingEnv<'tcx> { let param_env = tcx.param_env(def_id.to_def_id()); TypingEnv::new(param_env, ty::TypingMode::borrowck(tcx, def_id)) } - /// Ideally we just use `TypingMode::post_typeck_until_borrowck`. + /// Ideally we just use `TypingMode::post_typeck_through_borrowck`. /// But that's not compatible with the old solver yet. /// /// FIXME: this should not be needed in the long term. - pub fn post_typeck_until_borrowck_for_mir_build( + pub fn post_typeck_through_borrowck_for_mir_build( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> TypingEnv<'tcx> { - if tcx.use_typing_mode_post_typeck_until_borrowck() { + if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingEnv::new(tcx.param_env(def_id.to_def_id()), ty::TypingMode::borrowck(tcx, def_id)) } else { // FIXME(#132279): We're in a body, we should use a typing @@ -1210,7 +1210,7 @@ impl<'tcx> TypingEnv<'tcx> { TypingMode::Coherence | TypingMode::Reflection | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => {} TypingMode::PostAnalysis | TypingMode::Codegen => return self.as_query_input(value), } @@ -1235,7 +1235,7 @@ impl<'tcx> TypingEnv<'tcx> { TypingMode::Coherence | TypingMode::Reflection | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis => {} TypingMode::Codegen => return self.as_query_input(value), diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 3c4888a05d6e9..7e6c9f9ac6565 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -496,7 +496,7 @@ fn construct_fn<'tcx>( ); } - let typing_mode = if tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_mode = if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingMode::borrowck(tcx, fn_def) } else { // FIXME(#132279): This should be able to reveal opaque @@ -606,7 +606,7 @@ fn construct_const<'a, 'tcx>( _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; - let typing_mode = if tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_mode = if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingMode::borrowck(tcx, def) } else { // FIXME(#132279): This should be able to reveal opaque diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 06f48e3ccebe2..fd1215cfdad9b 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -960,7 +960,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { tcx: self.tcx, typeck_results, module: self.tcx.parent_module(self.hir_id), - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build( + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build( self.tcx, self.def_id, ), diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 5d421f6c3c885..881b50de017f8 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -25,7 +25,7 @@ pub(crate) fn check_tail_calls(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), E tcx, thir, found_errors: Ok(()), - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def), is_closure, caller_def_id: def, }; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index e83c3560a1ee9..f1423c2c4b152 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1091,7 +1091,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { body_target_features, assignment_info: None, in_union_destructure: false, - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def), inside_adt: false, warnings: &mut warnings, suggest_unsafe_block: true, diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 9ee80e229ed71..39a076a86afd8 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -107,7 +107,7 @@ impl<'tcx> ThirBuildCx<'tcx> { Self { tcx, thir: Thir::new(body_type), - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def), typeck_results, body_owner: def.to_def_id(), apply_adjustments: !find_attr!(tcx, hir_id, CustomMir(..)), 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 b434bd17e2d8e..72c2ffbe957e7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -37,7 +37,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err tcx, thir: &*thir, typeck_results, - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def_id), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def_id), hir_source: tcx.local_def_id_to_hir_id(def_id), let_source: LetSource::None, pattern_arena: &pattern_arena, diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 53739284f8c0f..6f4a98b1765e8 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -770,7 +770,7 @@ where ty::TypingMode::Coherence | ty::TypingMode::Reflection | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } => { bug!() } 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 5262f849bf764..dcab703546a7e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -529,7 +529,7 @@ where let assemble_impls = match self.typing_mode() { TypingMode::Coherence => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -1136,7 +1136,7 @@ where let opaque_types = match self.typing_mode() { TypingMode::Typeck { .. } => self.opaques_with_sub_unified_hidden_type(self_ty), TypingMode::Coherence - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Reflection diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 3b372876f574b..54f5a196b4154 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -774,7 +774,7 @@ where let skip_erased_attempt = match typing_mode { TypingMode::Reflection | TypingMode::Coherence => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::Codegen | TypingMode::PostAnalysis @@ -1963,7 +1963,7 @@ fn should_rerun_after_erased_canonicalization( RerunCondition::OpaqueInStorage(defids), TypingMode::PostBorrowck { defined_opaque_types: opaques } | TypingMode::Typeck { defining_opaque_types_and_generators: opaques } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaques }, + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: opaques }, ) => opaque_in_storage(opaques, defids), // ============================= (RerunCondition::AnyOpaqueHasInferAsHidden, TypingMode::Typeck { .. }) => { @@ -1975,7 +1975,7 @@ fn should_rerun_after_erased_canonicalization( | TypingMode::PostAnalysis | TypingMode::Codegen | TypingMode::Reflection - | TypingMode::PostTypeckUntilBorrowck { .. }, + | TypingMode::PostTypeckThroughBorrowck { .. }, ) => RerunDecision::No, // ============================= ( @@ -1997,7 +1997,7 @@ fn should_rerun_after_erased_canonicalization( ( RerunCondition::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(defids), TypingMode::PostBorrowck { defined_opaque_types: opaques } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaques }, + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: opaques }, ) => opaque_in_storage(opaques, defids), } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index f8c4597dce654..49e5744cfe46c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -350,7 +350,7 @@ where } // Outside of coherence, we treat the associated item as rigid instead. ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis | ty::TypingMode::Reflection diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index 675477ca7180a..08a602d78f354 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -41,7 +41,7 @@ where self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } TypingMode::Typeck { defining_opaque_types_and_generators: defining_opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { let Some(def_id) = def_id .as_local() .filter(|&def_id| defining_opaque_types.contains(&def_id.into())) @@ -86,7 +86,7 @@ where // computed in HIR typeck as the initial value. match self.typing_mode().assert_not_erased() { TypingMode::Typeck { .. } => {} - TypingMode::PostTypeckUntilBorrowck { .. } => { + TypingMode::PostTypeckThroughBorrowck { .. } => { let actual = cx .type_of_opaque_hir_typeck(def_id) .instantiate(cx, opaque_ty.args); 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 1d3008da399dc..22e68c99d2cb6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1354,7 +1354,7 @@ where // We're inferring regions of opaque types, but // the type itself is already fully known, no way // to leak the hidden type. - TypingMode::PostTypeckUntilBorrowck { .. } => {} + TypingMode::PostTypeckThroughBorrowck { .. } => {} // We're inferring the hidden type of opaques, could // leak types through it. TypingMode::Typeck { .. } => { @@ -1799,7 +1799,7 @@ where | TypingMode::PostAnalysis | TypingMode::Reflection | TypingMode::Codegen - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } => {} } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a29309c71e879..afc6c45d338e5 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2962,8 +2962,8 @@ written to standard error output)"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_post_typeck` instead of this field")] - typing_mode_post_typeck_until_borrowck: bool = (false, parse_bool, [TRACKED], - "enable `TypingMode::PostTypeckUntilBorrowck`, changing the way opaque types are handled during MIR borrowck"), + typing_mode_post_typeck_through_borrowck: bool = (false, parse_bool, [TRACKED], + "enable `TypingMode::PostTypeckThroughBorrowck`, changing the way opaque types are handled during MIR borrowck"), #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] ub_checks: Option = (None, parse_opt_bool, [TRACKED], "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 29563c0262621..d1064ba03948d 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -463,7 +463,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< match typing_mode { TypingMode::Coherence | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } => false, TypingMode::PostAnalysis | TypingMode::Codegen => { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 5e834c8c4059d..7b09baf7fe03e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -328,7 +328,7 @@ where defining_opaque_types_and_generators } TypingMode::Coherence - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } | TypingMode::Reflection | TypingMode::PostAnalysis diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index ba480654bd84a..cf77d061d2baa 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -175,7 +175,7 @@ where TypingMode::Typeck { defining_opaque_types_and_generators } => { defining_opaque_types_and_generators } - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } | TypingMode::Reflection | TypingMode::PostAnalysis diff --git a/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs index d234f95fe7602..cc98a9ba6a935 100644 --- a/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs @@ -165,7 +165,7 @@ pub fn query_compute_implied_outlives_bounds<'tcx>( /* if cfg!(debug_assertions) { match ocx.infcx.typing_mode_raw() { TypingMode::Typeck { defining_opaque_types_and_generators: opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaque_types } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: opaque_types } | TypingMode::PostBorrowck { defined_opaque_types: opaque_types } => { assert!(opaque_types.is_empty()) } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 63f7c6dfc94fc..0eeb9f9ed976e 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -140,7 +140,7 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( match infcx.typing_mode_raw().assert_not_erased() { // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE), TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => {} TypingMode::Coherence => { @@ -429,7 +429,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx match self.selcx.typing_mode() { // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => ty.super_fold_with(self), TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { let recursion_limit = self.cx().recursion_limit(); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6cea4a9300824..5d7be99f7907a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1035,7 +1035,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // get a result which isn't correct for all monomorphizations. match selcx.typing_mode() { TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } => { debug!( diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index b4dffab26d1e4..aee900937f4cc 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.infcx.typing_mode_raw().assert_not_erased() { TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => ty.try_super_fold_with(self)?, TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 05b4ba6a7180c..432fa2e142d88 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1389,7 +1389,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This is likely fixed by better caching in general in the new solver. // See: . TypingMode::Typeck { defining_opaque_types_and_generators: defining_opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { defining_opaque_types.is_empty() || (!pred.has_opaque_types() && !pred.has_coroutines()) } @@ -2435,7 +2435,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::Codegen | TypingMode::ErasedNotCoherence(_) @@ -2787,7 +2787,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { TypingMode::PostAnalysis | TypingMode::Reflection | TypingMode::Codegen - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } => false, TypingMode::Coherence => { unreachable!("old solver coherence") diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 1a868ba4b8cee..0ded7482bb6c4 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -163,7 +163,7 @@ fn resolve_associated_item<'tcx>( match typing_env.typing_mode().assert_not_erased() { ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::PostBorrowck { .. } => false, ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index bcae974daab7e..83f9f6d2f87f0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -85,7 +85,7 @@ fn layout_of<'tcx>( } ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::ErasedNotCoherence(_) @@ -551,7 +551,7 @@ fn layout_of_uncached<'tcx>( ty::TypingMode::Codegen => {} ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::ErasedNotCoherence(_) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index d50f6521441d5..d6d4d27764c46 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -111,16 +111,16 @@ pub enum TypingMode { /// } /// ``` Typeck { defining_opaque_types_and_generators: I::LocalDefIds }, - /// `PostTypeckUntilBorrowck` is used after `Typeck` has finished, up to and including borrowck, + /// `PostTypeckThroughBorrowck` is used after `Typeck` has finished, up to and including borrowck, /// for anything that accesses typeck results. This is the behavior that's used mainly in borrowck, /// but, for example, also in late lints and other analyses while building MIR. The behavior of - /// `PostTypeckUntilBorrowck` is identical to `TypingMode::Typeck` except that the initial value for + /// `PostTypeckThroughBorrowck` is identical to `TypingMode::Typeck` except that the initial value for /// opaque types is the type computed during HIR typeck with unique unconstrained region inference variables. /// /// This is currently only used by the new solver as it results in new /// non-universal defining uses of opaque types, which is a breaking change. /// See tests/ui/impl-trait/non-defining-use/as-projection-term.rs. - PostTypeckUntilBorrowck { defining_opaque_types: I::LocalDefIds }, + PostTypeckThroughBorrowck { defining_opaque_types: I::LocalDefIds }, /// Any analysis after borrowck for a given body should be able to use all the /// hidden types defined by borrowck, without being able to define any new ones. /// @@ -191,8 +191,8 @@ impl PartialEq for TypingModeEqWrapper { TypingMode::Typeck { defining_opaque_types_and_generators: r }, ) => l == r, ( - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: l }, - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: r }, + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: l }, + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: r }, ) => l == r, ( TypingMode::PostBorrowck { defined_opaque_types: l }, @@ -208,7 +208,7 @@ impl PartialEq for TypingModeEqWrapper { TypingMode::Coherence | TypingMode::Reflection | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen @@ -231,7 +231,7 @@ impl TypingMode { match self { TypingMode::Coherence => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -249,7 +249,7 @@ impl TypingMode { match self { TypingMode::Reflection => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Coherence | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -268,7 +268,7 @@ impl TypingMode { TypingMode::ErasedNotCoherence(_) => true, TypingMode::Coherence | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -288,8 +288,8 @@ impl TypingMode { TypingMode::Typeck { defining_opaque_types_and_generators } => { TypingMode::Typeck { defining_opaque_types_and_generators } } - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } } TypingMode::PostBorrowck { defined_opaque_types } => { TypingMode::PostBorrowck { defined_opaque_types } @@ -333,7 +333,7 @@ impl TypingMode { if defining_opaque_types.is_empty() { TypingMode::non_body_analysis() } else { - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } } } @@ -354,8 +354,8 @@ impl From> for TypingMode { TypingMode::Typeck { defining_opaque_types_and_generators } } - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } } TypingMode::PostBorrowck { defined_opaque_types } => { TypingMode::PostBorrowck { defined_opaque_types } @@ -627,7 +627,7 @@ where match infcx.typing_mode_raw().assert_not_erased() { TypingMode::Coherence | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis => infcx.cx().features().feature_bound_holds_in_crate(symbol), diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 257d0a776403e..445d9b09ba04d 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -1080,7 +1080,7 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl TypingMode::Typeck { .. } | TypingMode::Reflection | TypingMode::ErasedNotCoherence { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen => (), diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 054dff869e650..56d3c81734072 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -129,7 +129,7 @@ where } TypingMode::Typeck { .. } | TypingMode::Reflection - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen => structurally_relate_tys(relation, a, b), diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 35f8897afd4c4..e996f6684515a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -115,7 +115,7 @@ impl AliasTyKind { /// Rigidness becomes outdated when the surrounding typing mode or param env changes, /// because further normalization might be possible. /// We should also note that rigidness can be shared within some typing mode groups -/// if the param env is the same, e.g., `Typeck/PostTypeckUntilBorrowck` and +/// if the param env is the same, e.g., `Typeck/PostTypeckThroughBorrowck` and /// `PostAnalysis/Codegen`. /// /// We always reveal auto traits for rigid aliases and this can cause query cycle in From 71ee80ada9ea5a0686f0c787c298544df05f79b3 Mon Sep 17 00:00:00 2001 From: James Barford-Evans Date: Mon, 19 Oct 2026 10:41:20 +0100 Subject: [PATCH 05/18] Remove -Z option --- compiler/rustc_middle/src/ty/context.rs | 1 - compiler/rustc_session/src/options.rs | 3 --- 2 files changed, 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f338dbef3c077..8647c8be6206a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2857,7 +2857,6 @@ impl<'tcx> TyCtxt<'tcx> { #[allow(rustc::bad_opt_access)] pub fn use_typing_mode_post_typeck_through_borrowck(self) -> bool { self.next_trait_solver_globally() - || self.sess.opts.unstable_opts.typing_mode_post_typeck_through_borrowck } pub fn assumptions_on_binders(self) -> bool { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index afc6c45d338e5..7248a9c801d07 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2961,9 +2961,6 @@ written to standard error output)"), "in diagnostics, use heuristics to shorten paths referring to items"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), - #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_post_typeck` instead of this field")] - typing_mode_post_typeck_through_borrowck: bool = (false, parse_bool, [TRACKED], - "enable `TypingMode::PostTypeckThroughBorrowck`, changing the way opaque types are handled during MIR borrowck"), #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] ub_checks: Option = (None, parse_opt_bool, [TRACKED], "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), From 205d6ac9b8b309ebb6cf5676b7737255e582a3bd Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Fri, 28 Aug 2026 21:43:44 +0000 Subject: [PATCH 06/18] Add reference annotations for unions Let's link the relevant UI tests to the Reference's rules for unions. --- tests/ui/borrowck/borrowck-union-borrow-nested.rs | 2 ++ tests/ui/borrowck/borrowck-union-borrow.rs | 2 ++ tests/ui/consts/const-eval/union-const-eval-field.rs | 3 +++ tests/ui/consts/const-eval/union-ub.rs | 3 +++ tests/ui/macros/stringify.rs | 2 ++ tests/ui/nll/issue-45157.rs | 2 ++ tests/ui/nll/issue-57100.rs | 2 ++ tests/ui/parser/recover/recover-field-semi.rs | 2 ++ tests/ui/privacy/union-field-privacy-1.rs | 2 ++ tests/ui/privacy/union-field-privacy-2.rs | 2 ++ tests/ui/union/union-basic.rs | 3 +++ tests/ui/union/union-inherent-method.rs | 4 +++- tests/ui/union/union-modification.rs | 2 ++ tests/ui/union/union-nodrop.rs | 2 ++ tests/ui/union/union-repr-c.rs | 2 ++ tests/ui/union/union-transmute.rs | 6 ++++-- tests/ui/union/union.rs | 2 ++ 17 files changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/ui/borrowck/borrowck-union-borrow-nested.rs b/tests/ui/borrowck/borrowck-union-borrow-nested.rs index b3a6670fa4881..faf59a292c22a 100644 --- a/tests/ui/borrowck/borrowck-union-borrow-nested.rs +++ b/tests/ui/borrowck/borrowck-union-borrow-nested.rs @@ -29,3 +29,5 @@ fn main() { trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } impl Fake for T { } + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/borrowck/borrowck-union-borrow.rs b/tests/ui/borrowck/borrowck-union-borrow.rs index f01915398a412..3564defd3ea32 100644 --- a/tests/ui/borrowck/borrowck-union-borrow.rs +++ b/tests/ui/borrowck/borrowck-union-borrow.rs @@ -94,3 +94,5 @@ fn main() { } } } + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs index 2c9061a7a50f8..6ae8e8188dcfe 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.rs +++ b/tests/ui/consts/const-eval/union-const-eval-field.rs @@ -37,3 +37,6 @@ fn main() { assert_eq!(read_field2(), 1.0); assert_eq!(read_field3(), unsafe { UNION.field3 }); } + +//@ reference: items.union.fields.read +//@ reference: items.union.fields.validity diff --git a/tests/ui/consts/const-eval/union-ub.rs b/tests/ui/consts/const-eval/union-ub.rs index 0fa5d31285604..33bf5cc316735 100644 --- a/tests/ui/consts/const-eval/union-ub.rs +++ b/tests/ui/consts/const-eval/union-ub.rs @@ -40,3 +40,6 @@ const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; const BAD_UNION: Foo = unsafe { Bar { u8: 42 }.foo }; fn main() {} + +//@ reference: items.union.fields.intro +//@ reference: items.union.fields.validity diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 242a91cab7e77..304b568408c62 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -1001,3 +1001,5 @@ fn test_punct() { p!([ ,; ;, ** @@ $+$ >< <> ?? +== ], ",; ;, ** @@ $+$ >< <> ?? +=="); p!([ :#!@|$=&*,+;*~? ], ":#!@|$=&*,+;*~?"); } + +//@ reference: items.union.fieldless diff --git a/tests/ui/nll/issue-45157.rs b/tests/ui/nll/issue-45157.rs index 8d2bf22a03c9a..9c59bde7cb310 100644 --- a/tests/ui/nll/issue-45157.rs +++ b/tests/ui/nll/issue-45157.rs @@ -29,3 +29,5 @@ fn main() { println!("{} {}", mref, nref) } } + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/nll/issue-57100.rs b/tests/ui/nll/issue-57100.rs index f15929334bb40..bd31fd230fbf0 100644 --- a/tests/ui/nll/issue-57100.rs +++ b/tests/ui/nll/issue-57100.rs @@ -65,3 +65,5 @@ fn first_union() { } fn main() {} + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/parser/recover/recover-field-semi.rs b/tests/ui/parser/recover/recover-field-semi.rs index b6f235f8ad1c9..8ea8adff145b5 100644 --- a/tests/ui/parser/recover/recover-field-semi.rs +++ b/tests/ui/parser/recover/recover-field-semi.rs @@ -16,3 +16,5 @@ enum Baz { fn main() { let _ = Foo { foo: "" }; //~ ERROR mismatched types } + +//@ reference: items.union.syntax diff --git a/tests/ui/privacy/union-field-privacy-1.rs b/tests/ui/privacy/union-field-privacy-1.rs index 8a84bd86ae559..e64286146fd82 100644 --- a/tests/ui/privacy/union-field-privacy-1.rs +++ b/tests/ui/privacy/union-field-privacy-1.rs @@ -15,3 +15,5 @@ fn main() { unsafe { let m::U { b } = u; // OK let m::U { c } = u; //~ ERROR field `c` of union `U` is private }} + +//@ reference: items.union.ref.use diff --git a/tests/ui/privacy/union-field-privacy-2.rs b/tests/ui/privacy/union-field-privacy-2.rs index f02e0f8a9b95e..3c62efb8f7c4d 100644 --- a/tests/ui/privacy/union-field-privacy-2.rs +++ b/tests/ui/privacy/union-field-privacy-2.rs @@ -13,3 +13,5 @@ fn main() { let b = u.b; // OK let c = u.c; //~ ERROR field `c` of union `U` is private } + +//@ reference: items.union.ref.use diff --git a/tests/ui/union/union-basic.rs b/tests/ui/union/union-basic.rs index 027f994ab4c94..ec8a523faedb3 100644 --- a/tests/ui/union/union-basic.rs +++ b/tests/ui/union/union-basic.rs @@ -58,3 +58,6 @@ fn main() { local(); xcrate(); } + +//@ reference: items.union.common-storage +//@ reference: items.union.init.result diff --git a/tests/ui/union/union-inherent-method.rs b/tests/ui/union/union-inherent-method.rs index b3b0fec8c1f37..35f724fdb2f78 100644 --- a/tests/ui/union/union-inherent-method.rs +++ b/tests/ui/union/union-inherent-method.rs @@ -1,5 +1,4 @@ //@ run-pass -//@ reference: items.impl.inherent.allowed-items union U { a: u8, @@ -13,3 +12,6 @@ fn main() { let u = U { a: 10 }; assert_eq!(u.method(), 10); } + +//@ reference: items.impl.inherent.allowed-items +//@ reference: items.union.ref.use diff --git a/tests/ui/union/union-modification.rs b/tests/ui/union/union-modification.rs index 0f123395680b5..66ffe0e2e24e0 100644 --- a/tests/ui/union/union-modification.rs +++ b/tests/ui/union/union-modification.rs @@ -32,3 +32,5 @@ pub fn main() { assert_eq!(unsafe { foo_holder.inner_foo.bar }, 4); drop(foo_holder); } + +//@ reference: items.union.fields.write-safety diff --git a/tests/ui/union/union-nodrop.rs b/tests/ui/union/union-nodrop.rs index 401ed42f73bff..310f3b5e11e7d 100644 --- a/tests/ui/union/union-nodrop.rs +++ b/tests/ui/union/union-nodrop.rs @@ -64,3 +64,5 @@ fn main() { assert!(needs_drop::>()); assert!(needs_drop::>>()); } + +//@ reference: items.union.drop diff --git a/tests/ui/union/union-repr-c.rs b/tests/ui/union/union-repr-c.rs index 1367835e67781..84d633cc11b78 100644 --- a/tests/ui/union/union-repr-c.rs +++ b/tests/ui/union/union-repr-c.rs @@ -16,3 +16,5 @@ extern "C" { } fn main() {} + +//@ reference: type.union.layout diff --git a/tests/ui/union/union-transmute.rs b/tests/ui/union/union-transmute.rs index 879ee7a23dbd8..b578512fe07a3 100644 --- a/tests/ui/union/union-transmute.rs +++ b/tests/ui/union/union-transmute.rs @@ -1,6 +1,4 @@ //@ run-pass -//@ reference: items.union.common-storage -//@ reference: type.union.access union U { a: (u8, u8), @@ -25,3 +23,7 @@ fn main() { assert_eq!(w.a, 0b1_11111111_00000000000000000000000); } } + +//@ reference: items.union.common-storage +//@ reference: items.union.fields.intro +//@ reference: type.union.access diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index ae81708aa191c..751041343eb4a 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -47,3 +47,5 @@ pub fn main() { } let Foo { bar: _ } = foo; } + +//@ reference: items.union.pattern.safety From 2eef18704df645d8177bedc78f8f3b6c9f3c20db Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Tue, 25 Aug 2026 16:49:16 -0400 Subject: [PATCH 07/18] update to illumos sysroot 20210501 and update plaform note get illumos sysroot from mirror --- src/ci/docker/scripts/illumos-toolchain.sh | 9 +++++---- src/doc/rustc/src/platform-support/illumos.md | 9 +++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ci/docker/scripts/illumos-toolchain.sh b/src/ci/docker/scripts/illumos-toolchain.sh index 7a3ca875554ae..b284fca65f282 100644 --- a/src/ci/docker/scripts/illumos-toolchain.sh +++ b/src/ci/docker/scripts/illumos-toolchain.sh @@ -47,11 +47,12 @@ GCC_BASE="gcc-$GCC_VERSION" GCC_TAR="gcc-$GCC_VERSION.tar.xz" GCC_URL="https://ftp.gnu.org/gnu/gcc/$GCC_BASE/$GCC_TAR" -SYSROOT_VER='20181213-de6af22ae73b-v1' -SYSROOT_SUM='ee792d956dfa6967453cebe9286a149143290d296a8ce4b8a91d36bea89f8112' +# Originally downloaded from: +# https://github.com/illumos/sysroot/releases/download/$SYSROOT_VER/$SYSROOT_TAR" +SYSROOT_VER='20210501-e0b4275f34-v0' +SYSROOT_SUM='28d8f4f6d84331ff1e99ac3d68b917cf8174897a5c00171c5e493253eb1587f6' SYSROOT_TAR="illumos-sysroot-$SYSROOT_MACH-$SYSROOT_VER.tar.gz" -SYSROOT_URL='https://github.com/illumos/sysroot/releases/download/' -SYSROOT_URL+="$SYSROOT_VER/$SYSROOT_TAR" +SYSROOT_URL="https://ci-mirrors.rust-lang.org/rustc/$SYSROOT_TAR" SYSROOT_DIR="$PREFIX/sysroot" BINUTILS_VERSION='2.40' diff --git a/src/doc/rustc/src/platform-support/illumos.md b/src/doc/rustc/src/platform-support/illumos.md index c03238269d37a..f45c9b8421c30 100644 --- a/src/doc/rustc/src/platform-support/illumos.md +++ b/src/doc/rustc/src/platform-support/illumos.md @@ -40,3 +40,12 @@ The target supports C code. The illumos project makes available [prebuilt sysroot artefacts](https://github.com/illumos/sysroot) which can be used for cross compilation. The official Rust binaries are cross-compiled using these artefacts. + +## Target version requirements + +The host tools cross-compiled for this target should work on any +illumos distribution based on illumos sources later than the +date shown in the sysroot version tag. + +For details on illumos sysroot versions see: +[sysroot versions](https://github.com/illumos/sysroot/releases) From 0f64fe60db9c638fbb391af22c4d6a06f9e99886 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 22 Oct 2026 09:47:12 +0800 Subject: [PATCH 08/18] chore(triagebot): allow `llm-assisted` label to be set without write access --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 676ab4df6448a..528e6e2cc9462 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -26,6 +26,7 @@ allow-unauthenticated = [ "beta-nominated", "CI-spurious-*", "const-hack", + "llm-assisted", "llvm-*", "needs-fcp", "relnotes", From 88898fe7cdf0266cbd984089572cbb7075d145a0 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 21 Sep 2026 05:15:38 +0000 Subject: [PATCH 09/18] rmake: Rename the `symbols` to `obj` This module can contain various helpers for `object`, not strictly those that work with symbols. --- src/tools/run-make-support/src/lib.rs | 12 +++++++++++- .../run-make-support/src/{symbols.rs => obj.rs} | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) rename src/tools/run-make-support/src/{symbols.rs => obj.rs} (99%) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f800dd61e47d6..661c3518f64ee 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -16,11 +16,11 @@ pub mod diff; pub mod env; pub mod external_deps; pub mod linker; +pub mod obj; pub mod path_helpers; pub mod run; pub mod scoped_run; pub mod string; -pub mod symbols; pub mod targets; pub mod wasm; @@ -34,6 +34,16 @@ pub mod rfs { pub use crate::fs::*; } +/// Older version of the [`obj`] module. Prefer importing from there instead. +pub mod symbols { + pub use crate::obj::{ + ContainsAllSymbolSubstringsOutcome, ContainsAllSymbolsOutcome, + exported_dynamic_symbol_names, object_contains_all_symbol_substring, + object_contains_all_symbols, object_contains_any_symbol, + object_contains_any_symbol_substring, + }; +} + // Re-exports of third-party library crates. pub use bstr; pub use gimli; diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/obj.rs similarity index 99% rename from src/tools/run-make-support/src/symbols.rs rename to src/tools/run-make-support/src/obj.rs index 0e11360bd5a02..2c8685449b836 100644 --- a/src/tools/run-make-support/src/symbols.rs +++ b/src/tools/run-make-support/src/obj.rs @@ -1,3 +1,5 @@ +//! Helpers for working with types from the [`object`] crate. + use std::collections::BTreeSet; use std::path::Path; From 2dc48e704e03003487595612282c0616e68c095a Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sun, 20 Sep 2026 23:49:20 -0500 Subject: [PATCH 10/18] rmake: Add helpers for iterating symbols and objects --- src/tools/run-make-support/src/obj.rs | 90 ++++++++++++++++++++- tests/run-make/libstd-no-protected/rmake.rs | 44 +++------- 2 files changed, 101 insertions(+), 33 deletions(-) diff --git a/src/tools/run-make-support/src/obj.rs b/src/tools/run-make-support/src/obj.rs index 2c8685449b836..1acf85e7eb650 100644 --- a/src/tools/run-make-support/src/obj.rs +++ b/src/tools/run-make-support/src/obj.rs @@ -1,9 +1,95 @@ //! Helpers for working with types from the [`object`] crate. use std::collections::BTreeSet; -use std::path::Path; +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; +use std::path::{Path, PathBuf}; -use object::{self, Object, ObjectSymbol}; +use bstr::BStr; +pub use object::read::archive::ArchiveFile; +use object::{self, Object, ObjectSymbol, Symbol}; +pub use object::{File as ObjFile, Result as ObjResult}; + +use crate::rfs; + +/// Thin wrapper for owning data used by `object`, which may be either an archive or a single +/// object file. +pub struct BinFile { + path: PathBuf, + data: Vec, +} + +impl BinFile { + /// Read an archive or object file at `path`. + pub fn read_path>(path: P) -> Self { + let path = path.into(); + Self { data: rfs::read(&path), path } + } + + /// Access the owned buffer as an archive file. + pub fn parse_as_archive_file(&self) -> ObjResult> { + ArchiveFile::parse(self.data.as_slice()) + } + + /// Access the owned buffer as an archive file. + pub fn parse_as_obj_file(&self) -> ObjResult> { + ObjFile::parse(self.data.as_slice()) + } + + /// If the file is an archive, run the callback for each object file. If it is an object + /// file, the callback will run once. + /// + /// The callback receives the parsed object file and its name in the archive or on disk. + pub fn for_each_object(&self, mut f: impl FnMut(ObjFile<'_>, &BStr)) { + // Try as an archive first. + let as_archive = self.parse_as_archive_file(); + if let Ok(archive) = as_archive { + for member in archive.members() { + let member = member.expect("failed to access member"); + let obj_data = member.data(self.data.as_slice()).expect("failed to access object"); + let obj = ObjFile::parse(obj_data).expect("failed to parse object"); + f(obj, BStr::new(member.name())); + } + + return; + } + + // Fall back to parsing as an object file. + let as_obj = self.parse_as_obj_file(); + if let Ok(obj) = as_obj { + let path_os = self.path.as_os_str(); + let path = cfg_select! { + unix => path_os.as_bytes(), + _ => path_os + .to_str() + .unwrap_or_else(|| panic!("non-utf-8 path on non-unix: {:?}", self.path)) + .as_bytes(), + }; + f(obj, BStr::new(path)); + return; + } + + panic!( + "failed to parse {:?} as either an archive or a object file: {:?}, {:?}", + self.path, + as_archive.unwrap_err(), + as_obj.unwrap_err(), + ); + } + + /// Do something with each symbol in an archive or object file. + /// + /// The callback receives: + /// + /// * The symbol. + /// * The parsed object file that contains the symbol. + /// * The name of the object file in its archive or on disk. + pub fn for_each_symbol(&self, mut f: impl FnMut(Symbol<'_, '_>, &ObjFile<'_>, &BStr)) { + self.for_each_object(|obj, obj_path| { + obj.symbols().for_each(|sym| f(sym, &obj, obj_path)); + }); + } +} /// Given an [`object::File`], find the exported dynamic symbol names via /// [`object::Object::exports`]. This does not distinguish between which section the symbols appear diff --git a/tests/run-make/libstd-no-protected/rmake.rs b/tests/run-make/libstd-no-protected/rmake.rs index 75a1dcc4a7d0f..f907618966d3d 100644 --- a/tests/run-make/libstd-no-protected/rmake.rs +++ b/tests/run-make/libstd-no-protected/rmake.rs @@ -4,11 +4,9 @@ //@ only-x86_64-unknown-linux-gnu -use run_make_support::object::Endianness; -use run_make_support::object::read::archive::ArchiveFile; -use run_make_support::object::read::elf::{FileHeader as _, SectionHeader as _}; -use run_make_support::rfs::read; -use run_make_support::{has_prefix, has_suffix, object, path, rustc, shallow_find_files, target}; +use run_make_support::obj::BinFile; +use run_make_support::object::{Endianness, ObjectSymbol, SymbolFlags}; +use run_make_support::{has_prefix, has_suffix, object, rustc, shallow_find_files, target}; type FileHeader = run_make_support::object::elf::FileHeader64; type SymbolTable<'data> = run_make_support::object::read::elf::SymbolTable<'data, FileHeader>; @@ -21,41 +19,25 @@ fn main() { }); assert_eq!(libs.len(), 1); let libstd_path = libs.pop().unwrap(); - let archive_data = read(libstd_path); + let archive = BinFile::read_path(libstd_path); // Parse all the object files within the libstd archive, checking defined symbols. - let mut num_protected = 0; + let mut protected = Vec::new(); let mut num_symbols = 0; - let archive = ArchiveFile::parse(&*archive_data).unwrap(); - for member in archive.members() { - let member = member.unwrap(); - if member.name() == b"lib.rmeta" { - continue; + archive.for_each_symbol(|symbol, _obj, obj_name| { + if obj_name == "lib.rmeta" { + return; } - let data = member.data(&*archive_data).unwrap(); - - let header = FileHeader::parse(data).unwrap(); - let endian = header.endian().unwrap(); - let sections = header.sections(endian, data).unwrap(); - - for (section_index, section) in sections.enumerate() { - if section.sh_type(endian) == object::elf::SHT_SYMTAB { - let symbols = - SymbolTable::parse(endian, data, §ions, section_index, section).unwrap(); - for symbol in symbols.symbols() { - if symbol.st_visibility() == object::elf::STV_PROTECTED { - num_protected += 1; - } - num_symbols += 1; - } - } + if symbol.flags().elf_visibility().expect("non-elf file") == object::elf::STV_PROTECTED { + protected.push(String::from_utf8_lossy(symbol.name_bytes().unwrap()).into_owned()); } - } + num_symbols += 1; + }); // If there were no symbols at all, then something is wrong with the test. assert_ne!(num_symbols, 0); // The purpose of this test - check that no symbols have protected visibility. - assert_eq!(num_protected, 0); + assert!(protected.is_empty(), "found protected symbols {protected:#?}"); } From 01844ed7e3c4520e5f5d2919c06e5e8486d0a865 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Thu, 22 Oct 2026 11:03:49 +0200 Subject: [PATCH 11/18] Remove docs mentioning instability of wasm64 Memory64 is merged into the spec since 2025-07-23 (WASM 3.0). --- .../platform-support/wasm64-unknown-unknown.md | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md index cc21da11f4de1..32253fe4ab123 100644 --- a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md @@ -30,16 +30,8 @@ is 8-bytes large as well as pointers. The tradeoff, though, is that the maximum memory size is now the full 64-bit address space instead of the 4GB as limited by the 32-bit address space for `wasm32-unknown-unknown`. -This target is not a stable target. The [memory64] WebAssembly proposal is still -in-progress and not standardized. This means that there are not many engines -which implement the `memory64` feature and if they do they're likely behind a -flag, for example: - -* Nodejs - `--experimental-wasm-memory64` -* Wasmtime - `--wasm memory64` - -Also note that at this time the `wasm64-unknown-unknown` target assumes the -presence of other merged wasm proposals such as (with their LLVM feature flags): +Note that at this time the `wasm64-unknown-unknown` target assumes the presence +of other merged wasm proposals such as (with their LLVM feature flags): * [Bulk memory] - `+bulk-memory` * Mutable imported globals - `+mutable-globals` @@ -54,11 +46,6 @@ The `wasm64-unknown-unknown` target intends to match the default Clang targets for its `"C"` ABI, which is likely to be the same as Clang's `wasm32-unknown-unknown` largely. -> **Note**: due to the relatively early-days nature of this target when working -> with this target you may encounter LLVM bugs. If an assertion hit or a bug is -> found it's recommended to open an issue either with rust-lang/rust or ideally -> with LLVM itself. - This target does not support `panic=unwind` at this time. ## Building the target From 92e885a8baf8a719b83524fac3edc20ed0e42a59 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 22 Oct 2026 10:51:35 +0200 Subject: [PATCH 12/18] update PassBuilder constructor calls --- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index fbb810d5423b2..2abdcd95a0fe8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -732,7 +732,11 @@ extern "C" LLVMRustResult LLVMRustOptimize( PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } +#if LLVM_VERSION_GE(24, 0) + auto PB = PassBuilder(TheModule->getContext(), TM, PTO, PGOOpt, &PIC); +#else auto PB = PassBuilder(TM, PTO, PGOOpt, &PIC); +#endif LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; @@ -1201,8 +1205,18 @@ extern "C" LLVMRustResult LLVMRustPrintModule(LLVMModuleRef M, const char *Path, } extern "C" void LLVMRustPrintPasses() { +#if LLVM_VERSION_GE(24, 0) + LLVMContextRef CtxRef = LLVMRustContextCreate(); + PassBuilder PB(*unwrap(CtxRef)); +#else PassBuilder PB; +#endif + PB.printPassNames(outs()); + +#if LLVM_VERSION_GE(24, 0) + LLVMContextDispose(CtxRef); +#endif } extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, @@ -1554,7 +1568,11 @@ extern "C" LLVMRustBuffer *LLVMRustModuleSerialize(LLVMModuleRef M, { auto OS = raw_string_ostream(Ret->data); { +#if LLVM_VERSION_GE(24, 0) + PassBuilder PB(unwrap(M)->getContext()); +#else PassBuilder PB; +#endif LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; From 222c583a546ee42263278633dcd8c8743f0055c5 Mon Sep 17 00:00:00 2001 From: dianqk Date: Fri, 22 May 2026 18:03:10 +0800 Subject: [PATCH 13/18] Avoid cloning CFG-related analysis data. --- .../src/diagnostics/conflict_errors.rs | 7 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 77 ++++++++++++------- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 11 ++- .../rustc_mir_transform/src/ssa_range_prop.rs | 38 ++++----- 5 files changed, 78 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2f8ff159ceb0a..fe10ab9fe2466 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3843,8 +3843,11 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { location: Location, ) -> impl Iterator { if location.statement_index == 0 { - let predecessors = body.basic_blocks.predecessors()[location.block].to_vec(); - Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) + Either::Left( + body.basic_blocks.predecessors()[location.block] + .iter() + .map(|&bb| body.terminator_loc(bb)), + ) } else { Either::Right(std::iter::once(Location { statement_index: location.statement_index - 1, diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 41e21749f3920..ab843950a71d4 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -15,44 +15,71 @@ use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK}; pub struct BasicBlocks<'tcx> { basic_blocks: IndexVec>, /// Use an `Arc` so we can share the cache when we clone the MIR body, as borrowck does. - cache: Arc, + cache: Arc, } // Typically 95%+ of basic blocks have 4 or fewer predecessors. -type Predecessors = IndexVec>; +pub type Predecessors = IndexVec>; #[derive(Clone, Default, Debug)] -struct Cache { +pub struct CfgCache { predecessors: OnceLock, reverse_postorder: OnceLock>, dominators: OnceLock>, } +impl CfgCache { + #[inline] + pub fn dominators(self: &Arc, bbs: &BasicBlocks<'_>) -> &Dominators { + debug_assert!(Arc::ptr_eq(self, &bbs.cache)); + self.dominators.get_or_init(|| dominators(bbs)) + } + + #[inline] + pub fn reverse_postorder(self: &Arc, bbs: &BasicBlocks<'_>) -> &[BasicBlock] { + debug_assert!(Arc::ptr_eq(self, &bbs.cache)); + self.reverse_postorder.get_or_init(|| { + let mut rpo: Vec<_> = Postorder::new(&bbs.basic_blocks, START_BLOCK, None).collect(); + rpo.reverse(); + rpo + }) + } + + #[inline] + pub fn predecessors(self: &Arc, bbs: &BasicBlocks<'_>) -> &Predecessors { + debug_assert!(Arc::ptr_eq(self, &bbs.cache)); + self.predecessors.get_or_init(|| { + let mut preds = IndexVec::from_elem(SmallVec::new(), &bbs.basic_blocks); + for (bb, data) in bbs.basic_blocks.iter_enumerated() { + for succ in data.terminator().successors() { + preds[succ].push(bb); + } + } + preds + }) + } +} + impl<'tcx> BasicBlocks<'tcx> { #[inline] pub fn new(basic_blocks: IndexVec>) -> Self { - BasicBlocks { basic_blocks, cache: Arc::new(Cache::default()) } + BasicBlocks { basic_blocks, cache: Arc::new(CfgCache::default()) } + } + + #[inline] + pub fn cfg_cache(&self) -> Arc { + Arc::clone(&self.cache) } #[inline] pub fn dominators(&self) -> &Dominators { - self.cache.dominators.get_or_init(|| dominators(self)) + self.cache.dominators(self) } /// Returns predecessors for each basic block. #[inline] pub fn predecessors(&self) -> &Predecessors { - self.cache.predecessors.get_or_init(|| { - let mut preds = IndexVec::from_elem(SmallVec::new(), &self.basic_blocks); - for (bb, data) in self.basic_blocks.iter_enumerated() { - if let Some(term) = &data.terminator { - for succ in term.successors() { - preds[succ].push(bb); - } - } - } - preds - }) + self.cache.predecessors(self) } /// Returns basic blocks in a reverse postorder. @@ -62,11 +89,7 @@ impl<'tcx> BasicBlocks<'tcx> { /// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder #[inline] pub fn reverse_postorder(&self) -> &[BasicBlock] { - self.cache.reverse_postorder.get_or_init(|| { - let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, None).collect(); - rpo.reverse(); - rpo - }) + self.cache.reverse_postorder(self) } /// Returns mutable reference to basic blocks. Invalidates CFG cache. @@ -100,11 +123,11 @@ impl<'tcx> BasicBlocks<'tcx> { pub fn invalidate_cfg_cache(&mut self) { if let Some(cache) = Arc::get_mut(&mut self.cache) { // If we only have a single reference to this cache, clear it. - *cache = Cache::default(); + *cache = CfgCache::default(); } else { // If we have several references to this cache, overwrite the pointer itself so other // users can continue to use their (valid) cache. - self.cache = Arc::new(Cache::default()); + self.cache = Arc::new(CfgCache::default()); } } } @@ -149,21 +172,21 @@ impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> { } // Done here instead of in `structural_impls.rs` because `Cache` is private, as is `basic_blocks`. -TrivialTypeTraversalImpls! { Cache } +TrivialTypeTraversalImpls! { CfgCache } -impl Encodable for Cache { +impl Encodable for CfgCache { #[inline] fn encode(&self, _s: &mut S) {} } -impl Decodable for Cache { +impl Decodable for CfgCache { #[inline] fn decode(_: &mut D) -> Self { Default::default() } } -impl StableHash for Cache { +impl StableHash for CfgCache { #[inline] fn stable_hash(&self, _: &mut Hcx, _: &mut StableHasher) {} } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 29ca694b6431b..f199354e18198 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -36,7 +36,7 @@ use crate::ty::{ TypeVisitableExt, TypingEnv, UserTypeAnnotationIndex, }; -mod basic_blocks; +pub mod basic_blocks; mod consts; pub mod coverage; mod generic_graph; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index d74581b00980d..07215976ef9f3 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -137,8 +137,8 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { 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 cfg_cache = body.basic_blocks.cfg_cache(); + let dominators = cfg_cache.dominators(&body.basic_blocks); let arena = DroplessArena::default(); let mut state = @@ -149,8 +149,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { state.assign(local, opaque); } - let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); - for bb in reverse_postorder { + for &bb in cfg_cache.reverse_postorder(&body.basic_blocks) { let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; state.visit_basic_block_data(bb, data); } @@ -395,7 +394,7 @@ struct VnState<'body, 'a, 'tcx> { /// - `Some(Some(op))` are successful computations. evaluated: IndexVec>>>, ssa: &'body SsaLocals, - dominators: Dominators, + dominators: &'a Dominators, reused_locals: DenseBitSet, arena: &'a DroplessArena, } @@ -406,7 +405,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { body: &Body<'tcx>, typing_env: ty::TypingEnv<'tcx>, ssa: &'body SsaLocals, - dominators: Dominators, + dominators: &'a Dominators, local_decls: &'body LocalDecls<'tcx>, arena: &'a DroplessArena, ) -> Self { diff --git a/compiler/rustc_mir_transform/src/ssa_range_prop.rs b/compiler/rustc_mir_transform/src/ssa_range_prop.rs index e6df6bbd9fb4e..f854e4c5a8d3c 100644 --- a/compiler/rustc_mir_transform/src/ssa_range_prop.rs +++ b/compiler/rustc_mir_transform/src/ssa_range_prop.rs @@ -13,7 +13,7 @@ use rustc_abi::WrappingRange; use rustc_const_eval::interpret::Scalar; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::dominators::Dominators; -use rustc_index::bit_set::DenseBitSet; +use rustc_middle::mir::basic_blocks::Predecessors; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{BasicBlock, Body, Location, Operand, Place, TerminatorKind, *}; use rustc_middle::ty::{TyCtxt, TypingEnv}; @@ -32,13 +32,13 @@ impl<'tcx> crate::MirPass<'tcx> for SsaRangePropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { 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 cfg_cache = body.basic_blocks.cfg_cache(); + let dominators = cfg_cache.dominators(&body.basic_blocks); + let predecessors = cfg_cache.predecessors(&body.basic_blocks); let mut range_set = - RangeSet::new(tcx, typing_env, body, &ssa, &body.local_decls, dominators); + RangeSet::new(tcx, typing_env, &ssa, &body.local_decls, dominators, predecessors); - let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); - for bb in reverse_postorder { + for &bb in cfg_cache.reverse_postorder(&body.basic_blocks) { let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; range_set.visit_basic_block_data(bb, data); } @@ -50,29 +50,21 @@ struct RangeSet<'tcx, 'body, 'a> { typing_env: TypingEnv<'tcx>, ssa: &'a SsaLocals, local_decls: &'body LocalDecls<'tcx>, - dominators: Dominators, + dominators: &'a Dominators, /// Known ranges at each locations. ranges: FxHashMap, Vec<(Location, WrappingRange)>>, - /// Determines if the basic block has a single unique predecessor. - unique_predecessors: DenseBitSet, + predecessors: &'a Predecessors, } impl<'tcx, 'body, 'a> RangeSet<'tcx, 'body, 'a> { fn new( tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, - body: &Body<'tcx>, ssa: &'a SsaLocals, local_decls: &'body LocalDecls<'tcx>, - dominators: Dominators, + dominators: &'a Dominators, + predecessors: &'a Predecessors, ) -> Self { - let predecessors = body.basic_blocks.predecessors(); - let mut unique_predecessors = DenseBitSet::new_empty(body.basic_blocks.len()); - for bb in body.basic_blocks.indices() { - if predecessors[bb].len() == 1 { - unique_predecessors.insert(bb); - } - } RangeSet { tcx, typing_env, @@ -80,10 +72,14 @@ impl<'tcx, 'body, 'a> RangeSet<'tcx, 'body, 'a> { local_decls, dominators, ranges: FxHashMap::default(), - unique_predecessors, + predecessors, } } + fn has_unique_predecessor(&self, bb: BasicBlock) -> bool { + self.predecessors[bb].len() == 1 + } + /// Create a new known range at the location. fn insert_range(&mut self, place: Place<'tcx>, location: Location, range: WrappingRange) { assert!(self.is_ssa(place)); @@ -187,7 +183,7 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { continue; } let successor = target.start_location(); - if self.unique_predecessors.contains(successor.block) { + if self.has_unique_predecessor(successor.block) { assert_ne!(location.block, successor.block); let range = WrappingRange { start: val, end: val }; self.insert_range(place, successor, range); @@ -199,7 +195,7 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { let otherwise = targets.otherwise().start_location(); if place.ty(self.local_decls, self.tcx).ty.is_bool() && let [val] = targets.all_values() - && self.unique_predecessors.contains(otherwise.block) + && self.has_unique_predecessor(otherwise.block) { assert_ne!(location.block, otherwise.block); let range = if val.get() == 0 { From 31d8b41b9613328753c45babf9c1203928d8aa56 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Thu, 22 Oct 2026 13:05:28 +0200 Subject: [PATCH 14/18] use a default LLVMContext in LLVMRustPrintPasses --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 2abdcd95a0fe8..ffcef6df06e4f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1206,17 +1206,13 @@ extern "C" LLVMRustResult LLVMRustPrintModule(LLVMModuleRef M, const char *Path, extern "C" void LLVMRustPrintPasses() { #if LLVM_VERSION_GE(24, 0) - LLVMContextRef CtxRef = LLVMRustContextCreate(); - PassBuilder PB(*unwrap(CtxRef)); + LLVMContext C; + PassBuilder PB(C); #else PassBuilder PB; #endif PB.printPassNames(outs()); - -#if LLVM_VERSION_GE(24, 0) - LLVMContextDispose(CtxRef); -#endif } extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, From e6427699b51e7f52899ce794ccec82a4a1edb647 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 17 Oct 2026 20:18:21 +1100 Subject: [PATCH 15/18] clippy: Avoid hashing FileName This will make it possible to remove the compiler's Hash impl for FileName. --- src/tools/clippy/clippy_lints/src/inherent_impl.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 5790c3cce2606..db0f046d72811 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{LocalDefId, LocalModId}; use rustc_hir::{Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass, impl_lint_pass}; -use rustc_span::{FileName, Span}; +use rustc_span::{Span, StableSourceFileId}; use std::collections::hash_map::Entry; declare_clippy_lint! { @@ -63,7 +63,7 @@ impl MultipleInherentImpl { #[derive(Hash, Eq, PartialEq, Clone)] enum Criterion { Module(LocalModId), - File(FileName), + File(StableSourceFileId), Crate, } @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { InherentImplLintScope::Module => Criterion::Module(cx.tcx.parent_module(hir_id)), InherentImplLintScope::File => { let span = cx.tcx.hir_span(hir_id); - Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone()) + Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).stable_id) }, InherentImplLintScope::Crate => Criterion::Crate, }; From 9a82d1a75b8df54a9e174b6a73a5d45d48346862 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 17 Oct 2026 17:58:49 +1100 Subject: [PATCH 16/18] Sort `impl_dep_tracking_hash_via_hash!` --- compiler/rustc_session/src/config.rs | 98 ++++++++++++++-------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 5a96c0524c093..6f27f51583183 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3469,73 +3469,75 @@ pub(crate) mod dep_tracking { } impl_dep_tracking_hash_via_hash!( + // tidy-alphabetical-start (), + Align, AnnotateMoves, AutoDiff, - Offload, - bool, - usize, - NonZero, - u64, - Hash64, - String, - PathBuf, - lint::Level, - WasiExecModel, - u32, - FramePointer, - RelocModel, + BranchProtection, + CFGuard, + CFProtection, CodeModel, - TlsModel, - InstrumentCoverage, + CodegenRetagOptions, + CollapseMacroDebuginfo, CoverageOptions, + CrateType, + DebugInfo, + DebugInfoCompression, + Edition, + FmtDebug, + FramePointer, + FunctionReturn, + Hash64, + InliningThreshold, + InstrumentCoverage, InstrumentMcount, InstrumentMcountOpts, InstrumentXRay, - CrateType, + LanguageIdentifier, + LinkerPluginLto, + LocationDetail, + LtoCli, MergeFunctions, + MirStripDebugInfo, + NativeLib, + NextSolverConfig, + NonZero, + Offload, OnBrokenPipe, + OptLevel, + OutFileName, + OutputType, PanicStrategy, + PatchableFunctionEntry, + PathBuf, + PointerAuthOption, + Polonius, + RealFileName, + RelocModel, RelroLevel, - OptLevel, - LtoCli, - DebugInfo, - DebugInfoCompression, - MirStripDebugInfo, - CollapseMacroDebuginfo, - UnstableFeatures, - NativeLib, - SanitizerSet, - CFGuard, - CFProtection, - TargetTuple, - Edition, - LinkerPluginLto, + RemapPathScopeComponents, ResolveDocLinks, + RustcVersion, + SanitizerSet, + SourceFileHashAlgorithm, SplitDebuginfo, SplitDwarfKind, StackProtector, + String, SwitchWithOptPath, SymbolManglingVersion, SymbolVisibility, - RemapPathScopeComponents, - SourceFileHashAlgorithm, - OutFileName, - OutputType, - RealFileName, - LocationDetail, - FmtDebug, - BranchProtection, - LanguageIdentifier, - NextSolverConfig, - PatchableFunctionEntry, - Polonius, - InliningThreshold, - FunctionReturn, - Align, - CodegenRetagOptions, - RustcVersion, - PointerAuthOption, + TargetTuple, + TlsModel, + UnstableFeatures, + WasiExecModel, + bool, + lint::Level, + u32, + u64, + usize, + // tidy-alphabetical-end ); impl DepTrackingHash for (T1, T2) From d82fe8ab27bf2878a7d22a5759afbdcce7eb73e2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 17 Oct 2026 18:14:45 +1100 Subject: [PATCH 17/18] Avoid stdlib's `impl Hash for Path` for stable hashing A subtle consequence of the stage0 redesign is that the compiler must take care to avoid relying on any stdlib-provided Hash impl when computing stable hashes, or at least any such impl that is actually liable to change. This was noticed when trying to strengthen the provided Hash impl for Path, which triggered baffling CI failures because the stable hashes produced by the stage1 compiler (built against stage0 stdlib) were inconsistent with the ones that would have been produced by the stage2 compiler (built against in-tree stdlib). This PR aims to unblock changes to `impl Hash for Path`, by making the compiler not rely on it for stable hashing. It does not attempt to solve the broader problem of the compiler relying on stdlib hash details. --- .../rustc_data_structures/src/stable_hash.rs | 125 +++++++++++++++++- .../src/stable_hash/tests.rs | 34 +++++ compiler/rustc_session/src/config.rs | 26 +++- compiler/rustc_span/src/lib.rs | 22 +-- 4 files changed, 191 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_data_structures/src/stable_hash.rs b/compiler/rustc_data_structures/src/stable_hash.rs index 8e7ca5a75d861..91578b9fd4308 100644 --- a/compiler/rustc_data_structures/src/stable_hash.rs +++ b/compiler/rustc_data_structures/src/stable_hash.rs @@ -5,6 +5,7 @@ use std::num::NonZero; use rustc_index::bit_set::{self, DenseBitSet}; use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_macros::StableHash; use smallvec::SmallVec; use thin_vec::ThinVec; @@ -37,6 +38,25 @@ pub trait StableHashCtxt { fn assert_default_stable_hash_controls(&self, msg: &str); } +/// Dummy impl of [`StableHashCtxt`], for code that can't provide a real context, +/// and only wants to compute stable hashes for types that don't rely on the context. +pub struct DummyStableHashCtxt; + +impl StableHashCtxt for DummyStableHashCtxt { + fn stable_hash_span(&mut self, _span: RawSpan, _hasher: &mut StableHasher) { + panic!("method on dummy stable-hash context was unexpectedly called"); + } + fn def_path_hash(&self, _def_id: RawDefId) -> Fingerprint { + panic!("method on dummy stable-hash context was unexpectedly called"); + } + fn stable_hash_controls(&self) -> StableHashControls { + panic!("method on dummy stable-hash context was unexpectedly called"); + } + fn assert_default_stable_hash_controls(&self, _msg: &str) { + panic!("method on dummy stable-hash context was unexpectedly called"); + } +} + // A type used to work around `Span` not being visible in this crate. It is the same size as // `Span` but has a different alignment. pub struct RawSpan(pub u64); @@ -71,6 +91,18 @@ pub struct RawDefId(pub u32, pub u32); /// - `stable_hash()` must be independent of the host architecture. The /// `StableHasher` takes care of endianness and `isize`/`usize` platform /// differences. +/// +/// # Consistency across compiler stages +/// +/// Because the stage1 compiler is built against the bootstrap stdlib, but the stage2 +/// compiler uses in-tree stdlib, implementations of `StableHash` must not rely on `Hash` +/// impls that were provided or derived by the standard library. Doing so leads to weird +/// bugs and CI failures that can block changes to those stdlib hash impls. +/// +/// (Unfortunately, as of late 2026 we have many stable-hash impls that _do_ +/// leak details of stdlib hash impls.) +/// +/// See for more context. pub trait StableHash { fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher); } @@ -575,8 +607,97 @@ impl StableHash for bit_set::BitMatrix { impl_stable_traits_for_trivial_type!(::std::ffi::OsStr); -impl_stable_traits_for_trivial_type!(::std::path::Path); -impl_stable_traits_for_trivial_type!(::std::path::PathBuf); +impl StableHash for std::path::Path { + fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { + use std::path::{Component, Prefix}; + + /// Tag value to be mixed in with each kind of component/prefix. + #[derive(StableHash)] + enum Tag { + StartOfPath, + PrefixVerbatim, + PrefixVerbatimUNC, + PrefixVerbatimDisk, + PrefixDeviceNS, + PrefixUNC, + PrefixDisk, + RootDir, + CurDir, + ParentDir, + Normal, + EndOfPath, + } + + // Explicitly tag the start of each path, so that empty paths always hash something. + Tag::StartOfPath.stable_hash(hcx, hasher); + + for (i, component) in self.components().enumerate() { + // Mix in the index of each component, to avoid potentially trivial collisions + // between inputs like `("foo/bar", "baz")` and `("foo", "bar/baz")`. + i.stable_hash(hcx, hasher); + match component { + Component::Prefix(prefix) => match prefix.kind() { + Prefix::Verbatim(os_str) => { + Tag::PrefixVerbatim.stable_hash(hcx, hasher); + os_str.stable_hash(hcx, hasher); + } + Prefix::VerbatimUNC(host, share) => { + Tag::PrefixVerbatimUNC.stable_hash(hcx, hasher); + host.stable_hash(hcx, hasher); + share.stable_hash(hcx, hasher); + } + Prefix::VerbatimDisk(letter) => { + Tag::PrefixVerbatimDisk.stable_hash(hcx, hasher); + letter.stable_hash(hcx, hasher); + } + Prefix::DeviceNS(os_str) => { + Tag::PrefixDeviceNS.stable_hash(hcx, hasher); + os_str.stable_hash(hcx, hasher); + } + Prefix::UNC(host, share) => { + Tag::PrefixUNC.stable_hash(hcx, hasher); + host.stable_hash(hcx, hasher); + share.stable_hash(hcx, hasher); + } + Prefix::Disk(letter) => { + Tag::PrefixDisk.stable_hash(hcx, hasher); + letter.stable_hash(hcx, hasher); + } + }, + Component::RootDir => Tag::RootDir.stable_hash(hcx, hasher), + Component::CurDir => Tag::CurDir.stable_hash(hcx, hasher), + Component::ParentDir => Tag::ParentDir.stable_hash(hcx, hasher), + Component::Normal(os_str) => { + Tag::Normal.stable_hash(hcx, hasher); + os_str.stable_hash(hcx, hasher); + } + } + } + + // Explicitly tag the end of each path, so that empty paths always hash something. + // (Tagging the start and the end and the component-index is potentially overkill.) + Tag::EndOfPath.stable_hash(hcx, hasher); + } +} + +impl StableOrd for std::path::Path { + /// FIXME(Zalathar): Unstably sorting paths is pre-existing behavior, but potentially wrong. + const CAN_USE_UNSTABLE_SORT: bool = true; + /// Stdlib path sorting should (hopefully) not change. + const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); +} + +impl StableHash for std::path::PathBuf { + fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { + self.as_path().stable_hash(hcx, hasher); + } +} + +impl StableOrd for std::path::PathBuf { + const CAN_USE_UNSTABLE_SORT: bool = ::CAN_USE_UNSTABLE_SORT; + /// Stdlib path sorting should (hopefully) not change. + const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); +} // It is not safe to implement StableHash for HashSet, HashMap or any other collection type // with unstable but observable iteration order. diff --git a/compiler/rustc_data_structures/src/stable_hash/tests.rs b/compiler/rustc_data_structures/src/stable_hash/tests.rs index 163e441d5a47d..fa73b2ce16331 100644 --- a/compiler/rustc_data_structures/src/stable_hash/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hash/tests.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use super::*; // The tests below compare the computed hashes to particular expected values @@ -29,6 +31,19 @@ fn hash(t: &T) -> Hash128 { h.finish() } +/// Computes the stable hash of two values in sequence. +/// +/// This is similar to computing the stable hash of `(a, b)`, except that it +/// avoids relying on the actual impl of StableHash for tuples. +fn hash_two(a: &impl StableHash, b: &impl StableHash) -> Hash128 { + let hcx = &mut DummyStableHashCtxt; + let mut hasher = StableHasher::new(); + + a.stable_hash(hcx, &mut hasher); + b.stable_hash(hcx, &mut hasher); + hasher.finish() +} + // Check that bit set hash includes the domain size. #[test] fn test_hash_bit_set() { @@ -115,3 +130,22 @@ fn test_isize_compression() { check_hash(0xFF, 0xFFFFFFFFFFFFFFFF); check_hash(u64::MAX /* -1 */, 1); } + +#[test] +fn path_component_rebracketing() { + let hash_a = hash_two(&Path::new("alfa/bravo"), &Path::new("charlie")); + let hash_b = hash_two(&Path::new("alfa"), &Path::new("bravo/charlie")); + + assert_ne!(hash_a, hash_b); +} + +#[test] +fn empty_path_rebracketing() { + let nonempty_path = &Path::new("foo"); + let empty_path = &Path::new(""); + + let hash_a = hash_two(nonempty_path, empty_path); + let hash_b = hash_two(empty_path, nonempty_path); + + assert_ne!(hash_a, hash_b); +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 6f27f51583183..96d4e4ad82468 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3406,7 +3406,7 @@ pub(crate) mod dep_tracking { use rustc_abi::Align; use rustc_ast::attr::version::RustcVersion; use rustc_data_structures::fx::FxIndexMap; - use rustc_data_structures::stable_hash::StableHasher; + use rustc_data_structures::stable_hash::{DummyStableHashCtxt, StableHash, StableHasher}; use rustc_errors::LanguageIdentifier; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; @@ -3510,10 +3510,8 @@ pub(crate) mod dep_tracking { OutputType, PanicStrategy, PatchableFunctionEntry, - PathBuf, PointerAuthOption, Polonius, - RealFileName, RelocModel, RelroLevel, RemapPathScopeComponents, @@ -3626,6 +3624,28 @@ pub(crate) mod dep_tracking { } } + impl DepTrackingHash for PathBuf { + fn hash( + &self, + hasher: &mut StableHasher, + _error_format: ErrorOutputType, + _for_crate_hash: bool, + ) { + self.stable_hash(&mut DummyStableHashCtxt, hasher); + } + } + + impl DepTrackingHash for RealFileName { + fn hash( + &self, + hasher: &mut StableHasher, + _error_format: ErrorOutputType, + _for_crate_hash: bool, + ) { + self.stable_hash(&mut DummyStableHashCtxt, hasher); + } + } + // This is a stable hash because BTreeMap is a sorted container pub(crate) fn stable_hash( sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f0b53eac061ea..2207317a9227b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -32,7 +32,7 @@ // this crate without this line making `rustc_span` available. extern crate self as rustc_span; -use rustc_data_structures::stable_hash::StableHashCtxt; +use rustc_data_structures::stable_hash::{DummyStableHashCtxt, StableHashCtxt}; use rustc_data_structures::{AtomicRef, outline}; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_serialize::opaque::mem_encoder::MemEncoder; @@ -317,7 +317,7 @@ pub struct RealFileName { /// The inner workings of `RealFileName`. /// /// It contains the `name`, `working_directory` and `embeddable_name` components. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable, Hash)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, StableHash, Decodable, Encodable)] struct InnerRealFileName { /// The name. name: PathBuf, @@ -327,18 +327,18 @@ struct InnerRealFileName { embeddable_name: PathBuf, } -impl Hash for RealFileName { - #[inline] - fn hash(&self, state: &mut H) { +impl StableHash for RealFileName { + fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { + let RealFileName { local, maybe_remapped, scopes } = self; // To prevent #70924 from happening again we should only hash the // remapped path if that exists. This is because remapped paths to // sysroot crates (/rust/$hash or /rust/$version) remain stable even // if the corresponding local path changes. if !self.was_fully_remapped() { - self.local.hash(state); + local.stable_hash(hcx, hasher); } - self.maybe_remapped.hash(state); - self.scopes.bits().hash(state); + maybe_remapped.stable_hash(hcx, hasher); + scopes.bits().stable_hash(hcx, hasher); } } @@ -507,7 +507,7 @@ impl RealFileName { } /// Differentiates between real files and common virtual files. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, StableHash, Decodable, Encodable)] pub enum FileName { Real(RealFileName), /// Strings provided as `--cfg [cfgspec]`. @@ -2207,8 +2207,8 @@ impl StableSourceFileId { stable_crate_id: Option, ) -> Self { let mut hasher = StableHasher::new(); - filename.hash(&mut hasher); - stable_crate_id.hash(&mut hasher); + filename.stable_hash(&mut DummyStableHashCtxt, &mut hasher); + stable_crate_id.stable_hash(&mut DummyStableHashCtxt, &mut hasher); StableSourceFileId(hasher.finish()) } } From 63e2ea2be623e31047f026fcd00b469c5bda0cbf Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Thu, 22 Oct 2026 12:27:32 +0000 Subject: [PATCH 18/18] Declare through --- compiler/rustc_metadata/src/rmeta/decoder.rs | 24 ++- compiler/rustc_metadata/src/rmeta/encoder.rs | 18 +- compiler/rustc_metadata/src/rmeta/mod.rs | 20 +- .../rustc_middle/src/query/on_disk_cache.rs | 22 ++- .../src/coverage/expansion.rs | 6 +- compiler/rustc_span/src/hygiene.rs | 171 +++++++++--------- compiler/rustc_span/src/lib.rs | 1 + 7 files changed, 141 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f68cfcc0d388b..8ac88f0c9bd63 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -467,15 +467,21 @@ impl<'a, 'tcx> SpanDecoder for MetadataDecodeContext<'a, 'tcx> { let tcx = self.tcx; let cname = cdata.root.name(); - rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| { - debug!("SpecializedDecoder: decoding {}", id); - cdata - .root - .syntax_contexts - .get(cdata, id) - .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}")) - .decode((cdata, tcx)) - }) + rustc_span::hygiene::decode_syntax_context( + self, + &cdata.hygiene_context, + |_, external_ctxt| { + debug!("SpecializedDecoder: decoding {:?}", external_ctxt); + cdata + .root + .syntax_contexts + .get(cdata, external_ctxt) + .unwrap_or_else(|| { + panic!("Missing SyntaxContext {external_ctxt:?} for crate {cname:?}") + }) + .decode((cdata, tcx)) + }, + ) } fn decode_expn_id(&mut self) -> ExpnId { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index dc8a117704ca4..cbc6851d8d719 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -83,8 +83,8 @@ pub(super) struct EncodeContext<'a, 'tcx> { // Used for both `Symbol`s and `ByteSymbol`s. symbol_index_table: FxHashMap, local_defs_remapping: LocalDefsRemapping, - syntax_context_remapping: HygieneRemappingResults, - local_expn_id_remapping: HygieneRemappingResults, + syntax_context_remapping: HygieneRemappingResults, + local_expn_id_remapping: HygieneRemappingResults, } /// If the current crate is a proc-macro, returns early with `LazyArray::default()`. @@ -198,12 +198,12 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { } expn_id.krate.encode(self); - let expn_index = match expn_id.as_local() { - Some(local_expn) => self.local_expn_id_remapping.map_id(local_expn).as_raw(), - None => expn_id.local_id, + let raw_expn_index = match expn_id.as_local() { + Some(local_expn) => self.local_expn_id_remapping.map_id(local_expn).as_u32(), + None => expn_id.local_id.as_u32(), }; - expn_index.encode(self); + raw_expn_index.encode(self); } fn encode_span(&mut self, span: Span) { @@ -2087,12 +2087,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { &Rc::clone(&self.hygiene_ctxt), &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table), |(this, syntax_contexts, _, _), ctxt, ctxt_data| { - let context = this.syntax_context_remapping.map_id(ctxt); - syntax_contexts.set_some(context.as_u32(), this.lazy(ctxt_data)); + let ctxt = this.syntax_context_remapping.map_id(ctxt); + syntax_contexts.set_some(ctxt, this.lazy(ctxt_data)); }, |(this, _, expn_data_table, expn_hash_table), expn_id, expn_data, hash| { if let Some(expn_id) = expn_id.as_local() { - let expn_index = this.local_expn_id_remapping.map_id(expn_id).as_raw(); + let expn_index = this.local_expn_id_remapping.map_id(expn_id); expn_data_table.set_some(expn_index, this.lazy(expn_data.expect("local expn"))); expn_hash_table.set_some(expn_index, this.lazy(hash)); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0410874c122a6..4d3c49497a6c2 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -48,7 +48,7 @@ use rustc_serialize::opaque::FileEncoder; use rustc_session::config::mitigation_coverage::DeniedPartialMitigation; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; +use rustc_span::hygiene::{DecodedSyntaxContext, ExpnIndex, MacroKind, SyntaxContextKey}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; @@ -209,9 +209,10 @@ enum LazyState { Previous(NonZero), } -type SyntaxContextTable = LazyTable>>; -type ExpnDataTable = LazyTable>>; -type ExpnHashTable = LazyTable>>; +type SyntaxContextTable = + LazyTable>>; +type ExpnDataTable = LazyTable>>; +type ExpnHashTable = LazyTable>>; #[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct ProcMacroData { @@ -343,6 +344,17 @@ pub(crate) struct CrateRootUnhashed { dep_extra_filenames: IndexVec, } +rustc_index::newtype_index! { + #[max = 0x1FFF_FFFF] // `u32::MAX` >> 3, as `SyntaxContext` should be fit in 29 bits (see `span_encoding`). + #[default] + pub(super) struct RemappedSyntaxContext {} +} + +rustc_index::newtype_index! { + #[default] + pub(super) struct RemappedLocalExpnIndex {} +} + #[derive(Default)] pub(crate) struct LocalDefsRemapping { /// See `Definitions::first_non_det_index`, it is just cached version of it. diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 14794b5cb73c7..3c7d73b4a1226 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -552,15 +552,19 @@ impl<'a, 'tcx> Decodable> for Vec { impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { fn decode_syntax_context(&mut self) -> SyntaxContext { let syntax_contexts = self.syntax_contexts; - rustc_span::hygiene::decode_syntax_context(self, self.hygiene_context, |this, id| { - // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. - // We look up the position of the associated `SyntaxData` and decode it. - let pos = syntax_contexts.get(&id).unwrap(); - this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); - data - }) - }) + rustc_span::hygiene::decode_syntax_context( + self, + self.hygiene_context, + |this, external_ctxt| { + // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. + // We look up the position of the associated `SyntaxData` and decode it. + let pos = syntax_contexts.get(&external_ctxt.as_u32()).unwrap(); + this.with_position(pos.to_usize(), |decoder| { + let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); + data + }) + }, + ) } fn decode_expn_id(&mut self) -> ExpnId { diff --git a/compiler/rustc_mir_transform/src/coverage/expansion.rs b/compiler/rustc_mir_transform/src/coverage/expansion.rs index 5e8d261ae1f41..237392c583803 100644 --- a/compiler/rustc_mir_transform/src/coverage/expansion.rs +++ b/compiler/rustc_mir_transform/src/coverage/expansion.rs @@ -106,14 +106,14 @@ pub(crate) fn build_expn_tree( let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, hir_info, graph); let mut nodes = FxIndexMap::default(); - let new_node = |&context: &SyntaxContext| ExpnNode::for_context(context); + let new_node = |context: SyntaxContext| ExpnNode::for_context(context); for from_mir::RawSpanFromMir { raw_span, bcb } in raw_spans { let span_with_bcb = SpanWithBcb { span: raw_span, bcb }; // Create a node for this span's enclosing expansion, and add the span to it. let context = span_with_bcb.span.ctxt(); - let node = nodes.entry(context).or_insert_with_key(new_node); + let node = nodes.entry(context).or_insert_with_key(|&c| new_node(c)); node.spans.push(span_with_bcb); // Now walk up the expansion call-site chain, creating nodes and registering children. @@ -123,7 +123,7 @@ pub(crate) fn build_expn_tree( let entry = nodes.entry(context); let node_existed = matches!(entry, IndexEntry::Occupied(_)); - let node = entry.or_insert_with_key(new_node); + let node = entry.or_insert_with_key(|&c| new_node(c)); node.child_contexts.insert(prev); if node_existed { diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index c107f6ce4f64c..180dd9061aba2 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -26,6 +26,7 @@ use std::cell::RefCell; use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; use std::sync::Arc; use std::{fmt, iter, mem}; @@ -48,24 +49,14 @@ use crate::source_map::SourceMap; use crate::symbol::{Symbol, kw, sym}; use crate::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, with_session_globals}; -/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". -/// -/// See for more explanation. -#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SyntaxContext(u32); - -impl From for SyntaxContext { - #[inline(always)] - fn from(value: u32) -> SyntaxContext { - SyntaxContext(value) - } -} - -impl Into for SyntaxContext { - #[inline(always)] - fn into(self) -> u32 { - self.0 - } +rustc_index::newtype_index! { + /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". + /// + /// See for more explanation. + #[max = 0x1FFF_FFFF] // `u32::MAX` >> 3, as `SyntaxContext` should be fit in 29 bits (see `span_encoding`). + #[debug_format = "#{}"] + #[default] + pub struct SyntaxContext {} } // To ensure correctness of incremental compilation, @@ -363,19 +354,26 @@ impl ExpnId { } #[derive(Default)] -pub struct HygieneRemappingResults { - pub remapping: FxHashMap, - pub first_non_det_index: T, +pub struct HygieneRemappingResults { + remapping: FxHashMap, + first_non_det_index: u32, + data: PhantomData<(TKey, TRemappedKey)>, } -impl + Copy> HygieneRemappingResults { +pub trait RemappableIdx = Hash + Eq + Copy; +impl, TRemappedKey: RemappableIdx + From> + HygieneRemappingResults +{ #[inline] - pub fn map_id(&self, idx: T) -> T { - if idx.into() < self.first_non_det_index.into() { - idx + pub fn map_id(&self, idx: TKey) -> TRemappedKey { + let raw_idx: u32 = idx.into(); + let remapped_idx = if raw_idx < self.first_non_det_index { + raw_idx } else { - self.remapping.get(&idx).copied().unwrap_or(idx) - } + self.remapping.get(&raw_idx).copied().unwrap_or(raw_idx) + }; + + TRemappedKey::from(remapped_idx) } } @@ -399,33 +397,36 @@ pub trait HygieneRemapper { assert!(prev.is_none(), "this function can be called only once") } - fn remapping_results(&self, hcx: &mut impl StableHashCtxt) -> HygieneRemappingResults + fn remapping_results( + &self, + hcx: &mut impl StableHashCtxt, + ) -> HygieneRemappingResults where - T: From + Hash + Eq + Copy, + T: RemappableIdx + From, { let start = self.first_non_det_index(); let range = start..self.len() as u32; - let mut indices_to_remap = range.map(|raw_id| T::from(raw_id)).collect::>(); + let mut indices_to_remap = range.collect::>(); indices_to_remap.sort_by_cached_key(|&key| { let hasher = &mut StableHasher::new(); - self.stable_hash(key, hcx, hasher); + self.stable_hash(T::from(key), hcx, hasher); hasher.finish() }); - let mut remapping = FxHashMap::::default(); + let mut remapping = FxHashMap::default(); for (idx, key) in indices_to_remap.into_iter().enumerate() { let from = key; - let to = T::from(start + idx as u32); + let to = start + idx as u32; if from != to { remapping.insert(from, to); } } - HygieneRemappingResults { remapping, first_non_det_index: T::from(start) } + HygieneRemappingResults { remapping, first_non_det_index: start, data: PhantomData } } } @@ -509,7 +510,7 @@ pub(crate) struct HygieneData { foreign_expn_data: FxHashMap, foreign_expn_hashes: FxHashMap, expn_hash_to_expn_id: UnhashMap, - syntax_context_data: Vec, + syntax_context_data: IndexVec, first_non_det_syntax_context: Option, first_non_det_local_expn_id: Option, syntax_context_map: FxHashMap, @@ -541,8 +542,8 @@ impl HygieneData { foreign_expn_hashes: FxHashMap::default(), expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), - syntax_context_data: vec![root_ctxt_data], - syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(), + syntax_context_data: IndexVec::from_elem_n(root_ctxt_data, 1), + syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext::root())).collect(), expn_data_disambiguators: UnhashMap::default(), first_non_det_syntax_context: None, first_non_det_local_expn_id: None, @@ -596,30 +597,30 @@ impl HygieneData { #[inline] fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].opaque + self.syntax_context_data[ctxt].opaque } #[inline] fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque + self.syntax_context_data[ctxt].opaque_and_semiopaque } /// See [`SyntaxContextData::outer_expn`] #[inline] fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { - self.syntax_context_data[ctxt.0 as usize].outer_expn + self.syntax_context_data[ctxt].outer_expn } /// The last macro expansion and its Transparency #[inline] fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { - let data = &self.syntax_context_data[ctxt.0 as usize]; + let data = &self.syntax_context_data[ctxt]; (data.outer_expn, data.outer_transparency) } #[inline] fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].parent + self.syntax_context_data[ctxt].parent } fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) { @@ -738,15 +739,16 @@ impl HygieneData { // Reserve a new syntax context. // The inserted dummy data can only be potentially accessed by nested `alloc_ctxt` calls, // the assert below ensures that it doesn't happen. - let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len()); - self.syntax_context_data + let ctxt = self + .syntax_context_data .push(SyntaxContextData { dollar_crate_name: sym::dummy, ..SyntaxContextData::root() }); + self.syntax_context_map.insert(key, ctxt); // Opaque and semi-opaque versions of the parent. Note that they may be equal to the // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques. - let parent_data = &self.syntax_context_data[parent.0 as usize]; + let parent_data = &self.syntax_context_data[parent]; assert_ne!(parent_data.dollar_crate_name, sym::dummy); let parent_opaque = parent_data.opaque; let parent_opaque_and_semiopaque = parent_data.opaque_and_semiopaque; @@ -768,7 +770,7 @@ impl HygieneData { }; // Fill the full data, now that we have it. - self.syntax_context_data[ctxt.as_u32() as usize] = SyntaxContextData { + self.syntax_context_data[ctxt] = SyntaxContextData { outer_expn: expn_id, outer_transparency: transparency, parent, @@ -797,7 +799,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb // The new contexts that need updating are at the end of the list and have `$crate` as a name. let mut to_update = vec![]; HygieneData::with(|data| { - for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() { + for (idx, scdata) in data.syntax_context_data.iter_enumerated().rev() { if scdata.dollar_crate_name == kw::DollarCrate { to_update.push((idx, kw::DollarCrate)); } else { @@ -807,12 +809,12 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb }); // The callback must be called from outside of the `HygieneData` lock, // since it will try to acquire it too. - for (idx, name) in &mut to_update { - *name = get_name(SyntaxContext::from_usize(*idx)); + for (ctxt, name) in &mut to_update { + *name = get_name(*ctxt); } HygieneData::with(|data| { - for (idx, name) in to_update { - data.syntax_context_data[idx].dollar_crate_name = name; + for (ctxt, name) in to_update { + data.syntax_context_data[ctxt].dollar_crate_name = name; } }) } @@ -857,29 +859,14 @@ pub fn debug_hygiene_data(verbose: bool) -> String { } impl SyntaxContext { - #[inline] - pub const fn root() -> Self { - SyntaxContext(0) + #[inline(always)] + pub const fn root() -> SyntaxContext { + SyntaxContext::from_u32(0) } #[inline] pub const fn is_root(self) -> bool { - self.0 == SyntaxContext::root().as_u32() - } - - #[inline] - pub const fn as_u32(self) -> u32 { - self.0 - } - - #[inline] - pub(crate) const fn from_u32(raw: u32) -> SyntaxContext { - SyntaxContext(raw) - } - - #[inline] - fn from_usize(raw: usize) -> SyntaxContext { - SyntaxContext(u32::try_from(raw).unwrap()) + self.as_u32() == SyntaxContext::root().as_u32() } /// Extend a syntax context with a given expansion and transparency. @@ -1070,7 +1057,7 @@ impl SyntaxContext { #[inline] pub(crate) fn dollar_crate_name(self) -> Symbol { - HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) + HygieneData::with(|data| data.syntax_context_data[self].dollar_crate_name) } #[inline] @@ -1107,12 +1094,6 @@ impl SyntaxContext { } } -impl fmt::Debug for SyntaxContext { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "#{}", self.0) - } -} - impl Span { /// Reuses the span but adds information like the kind of the desugaring and features that are /// allowed inside this span. @@ -1495,7 +1476,7 @@ impl HygieneEncodeContext { let latest_contexts = { mem::take(&mut h_ctxt.borrow_mut().latest_ctxts) }.into_iter(); for ctxt in latest_contexts { - let key = HygieneData::with(|data| data.syntax_context_data[ctxt.0 as usize].key()); + let key = HygieneData::with(|data| data.syntax_context_data[ctxt].key()); encode_ctxt(encoder, ctxt, &key); } @@ -1532,7 +1513,7 @@ impl HygieneEncodeContext { pub struct HygieneDecodeContext { // A cache mapping raw serialized per-crate syntax context ids to corresponding decoded // `SyntaxContext`s in the current global `HygieneData`. - remapped_ctxts: Lock>>, + remapped_ctxts: Lock>>, } /// Register an expansion which has been decoded from the on-disk-cache for the local crate. @@ -1599,6 +1580,22 @@ pub fn decode_expn_id( register_expn_id(krate, index, expn_data, hash) } +rustc_index::newtype_index! { + /// A syntax context that is obtained from metadata of an external crate and + /// was not yet remapped to local `SyntaxContext`. + #[encodable] + #[max = 0x1FFF_FFFF] // `u32::MAX` >> 3, as `SyntaxContext` should be fit in 29 bits (see `span_encoding`). + #[debug_format = "#decoded{}"] + pub struct DecodedSyntaxContext {} +} + +impl DecodedSyntaxContext { + #[inline(always)] + fn is_root(self) -> bool { + self.as_u32() == 0 + } +} + // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` @@ -1606,10 +1603,10 @@ pub fn decode_expn_id( pub fn decode_syntax_context( d: &mut D, context: &HygieneDecodeContext, - decode_data: impl FnOnce(&mut D, u32) -> SyntaxContextKey, + decode_data: impl FnOnce(&mut D, DecodedSyntaxContext) -> SyntaxContextKey, ) -> SyntaxContext { - let raw_id: u32 = Decodable::decode(d); - if raw_id == 0 { + let decoded_ctxt: DecodedSyntaxContext = Decodable::decode(d); + if decoded_ctxt.is_root() { trace!("decode_syntax_context: deserialized root"); // The root is special return SyntaxContext::root(); @@ -1618,19 +1615,19 @@ pub fn decode_syntax_context( // Look into the cache first. // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between // raw ids from different crate metadatas. - if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(raw_id) { + if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(decoded_ctxt) { return *ctxt; } // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let (parent, expn_id, transparency) = decode_data(d, raw_id); - let ctxt = + let (parent, expn_id, transparency) = decode_data(d, decoded_ctxt); + let remapped_ctxt = HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency)); - context.remapped_ctxts.lock().insert(raw_id, ctxt); + context.remapped_ctxts.lock().insert(decoded_ctxt, remapped_ctxt); - ctxt + remapped_ctxt } impl Encodable for LocalExpnId { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f0b53eac061ea..a46cee8ccb50f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -25,6 +25,7 @@ #![feature(negative_impls)] #![feature(read_buf)] #![feature(rustc_attrs)] +#![feature(trait_alias)] // tidy-alphabetical-end // The code produced by the `Encodable`/`Decodable` derive macros refer to