From bc1a5662647d537d0fe3c95d87c98492d290436c Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Tue, 17 Feb 2026 05:19:14 +0000 Subject: [PATCH 01/59] Prepare for merging from rust-lang/rust This updates the rust-version file to 3c9faa0d037b9eecda4a440cc482ff7f960fb8a5. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 28c3e88535f6..ba1dac73653e 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -7bee525095c0872e87c038c412c781b9bbb3f5dc +3c9faa0d037b9eecda4a440cc482ff7f960fb8a5 From 7f1734352e67625f58db15fc1970f6093bf7003b Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 18 Feb 2026 05:19:36 +0000 Subject: [PATCH 02/59] Prepare for merging from rust-lang/rust This updates the rust-version file to 8387095803f21a256a9a772ac1f9b41ed4d5aa0a. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index ba1dac73653e..ccb61b282a61 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -3c9faa0d037b9eecda4a440cc482ff7f960fb8a5 +8387095803f21a256a9a772ac1f9b41ed4d5aa0a From c57ecb082f5e6f8034df84c5f8d0778164b5b7e3 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 19 Feb 2026 05:19:11 +0000 Subject: [PATCH 03/59] Prepare for merging from rust-lang/rust This updates the rust-version file to e0cb264b814526acb82def4b5810e394a2ed294f. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index ccb61b282a61..befd6c8a9196 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -8387095803f21a256a9a772ac1f9b41ed4d5aa0a +e0cb264b814526acb82def4b5810e394a2ed294f From 8b03e83d2dec60884b07a9b51f419517cec43db7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Feb 2026 08:37:22 +0100 Subject: [PATCH 04/59] fix genmc build --- src/tools/miri/src/concurrency/genmc/shims.rs | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/tools/miri/src/concurrency/genmc/shims.rs b/src/tools/miri/src/concurrency/genmc/shims.rs index 4685dfd1b8dd..cac03a21afc5 100644 --- a/src/tools/miri/src/concurrency/genmc/shims.rs +++ b/src/tools/miri/src/concurrency/genmc/shims.rs @@ -24,24 +24,22 @@ fn handle_assume_block<'tcx>( } } +/// Small helper to get the arguments of an intercepted function call. +fn get_fn_args<'tcx, const N: usize>( + instance: ty::Instance<'tcx>, + args: &[FnArg<'tcx>], +) -> InterpResult<'tcx, [OpTy<'tcx>; N]> { + let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? + if let Ok(ops) = args.try_into() { + return interp_ok(ops); + } + panic!("{} is a diagnostic item expected to have {} arguments", instance, N); +} + // Handling of code intercepted by Miri in GenMC mode, such as assume statement or `std::sync::Mutex`. impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { - /// Small helper to get the arguments of an intercepted function call. - fn get_fn_args( - &self, - instance: ty::Instance<'tcx>, - args: &[FnArg<'tcx>], - ) -> InterpResult<'tcx, [OpTy<'tcx>; N]> { - let this = self.eval_context_ref(); - let args = this.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? - if let Ok(ops) = args.try_into() { - return interp_ok(ops); - } - panic!("{} is a diagnostic item expected to have {} arguments", instance, N); - } - /**** Blocking functionality ****/ /// Handle a thread getting blocked by a user assume (not an automatically generated assume). @@ -202,15 +200,15 @@ fn genmc_intercept_function( // NOTE: When adding new intercepted functions here, they must also be added to `fn get_function_kind` in `concurrency/genmc/scheduling.rs`. use rustc_span::sym; if this.tcx.is_diagnostic_item(sym::sys_mutex_lock, instance.def_id()) { - let [mutex] = this.get_fn_args(instance, args)?; + let [mutex] = get_fn_args(instance, args)?; let mutex = this.deref_pointer(&mutex)?; this.intercept_mutex_lock(mutex)?; } else if this.tcx.is_diagnostic_item(sym::sys_mutex_try_lock, instance.def_id()) { - let [mutex] = this.get_fn_args(instance, args)?; + let [mutex] = get_fn_args(instance, args)?; let mutex = this.deref_pointer(&mutex)?; this.intercept_mutex_try_lock(mutex, dest)?; } else if this.tcx.is_diagnostic_item(sym::sys_mutex_unlock, instance.def_id()) { - let [mutex] = this.get_fn_args(instance, args)?; + let [mutex] = get_fn_args(instance, args)?; let mutex = this.deref_pointer(&mutex)?; this.intercept_mutex_unlock(mutex)?; } else { From 054d4af414fe4d6a58502b30174b501636272059 Mon Sep 17 00:00:00 2001 From: Yang Lin Date: Fri, 13 Feb 2026 17:24:38 +0800 Subject: [PATCH 05/59] Print a warning when trying to open a file in `/proc` --- src/tools/miri/src/diagnostics.rs | 3 ++ src/tools/miri/src/shims/unix/fs.rs | 17 +++++++++- .../miri/tests/pass/open_a_file_in_proc.rs | 11 +++++++ .../tests/pass/open_a_file_in_proc.stderr | 32 +++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/tools/miri/tests/pass/open_a_file_in_proc.rs create mode 100644 src/tools/miri/tests/pass/open_a_file_in_proc.stderr diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 64c7096fc5c2..612023c4f486 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -149,6 +149,7 @@ pub enum NonHaltingDiagnostic { failure_ordering: AtomicReadOrd, effective_failure_ordering: AtomicReadOrd, }, + FileInProcOpened, } /// Level of Miri specific diagnostics @@ -654,6 +655,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { | ProgressReport { .. } | WeakMemoryOutdatedLoad { .. } => ("tracking was triggered here".to_string(), DiagLevel::Note), + FileInProcOpened => ("open a file in `/proc`".to_string(), DiagLevel::Warning), }; let title = match &e { @@ -701,6 +703,7 @@ pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { }; format!("GenMC currently does not model the failure ordering for `compare_exchange`. {was_upgraded_msg}. Miri with GenMC might miss bugs related to this memory access.") } + FileInProcOpened => format!("files in `/proc` can bypass the Abstract Machine and might not work properly in Miri") }; let notes = match &e { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index a01755ef95ae..d82a4d231315 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -7,7 +7,7 @@ rename, }; use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; use std::time::SystemTime; use rustc_abi::Size; @@ -355,6 +355,21 @@ fn open( let path_raw = this.read_pointer(path_raw)?; let path = this.read_path_from_c_str(path_raw)?; + + match path::absolute(&path) { + Ok(path) => { + // "/proc" does not work properly from inside Miri, warn about opening files there. + if matches!( + this.tcx.sess.target.os, + Os::Linux | Os::Android | Os::Illumos | Os::Solaris + ) && (path == Path::new("/proc") || path.starts_with("/proc/")) + { + this.machine.emit_diagnostic(NonHaltingDiagnostic::FileInProcOpened); + } + } + Err(_) => { /* when the path is empty, it is also unrelative to "/proc" issue */ } + } + let flag = this.read_scalar(flag)?.to_i32()?; let mut options = OpenOptions::new(); diff --git a/src/tools/miri/tests/pass/open_a_file_in_proc.rs b/src/tools/miri/tests/pass/open_a_file_in_proc.rs new file mode 100644 index 000000000000..8c9887656d38 --- /dev/null +++ b/src/tools/miri/tests/pass/open_a_file_in_proc.rs @@ -0,0 +1,11 @@ +//@compile-flags: -Zmiri-disable-isolation +//@only-target: linux android illumos +//@ignore-host: windows + +fn main() { + let _ = match std::fs::File::open("/proc/doesnotexist ") { + Ok(_f) => {} + Err(_msg) => {} + }; + (); +} diff --git a/src/tools/miri/tests/pass/open_a_file_in_proc.stderr b/src/tools/miri/tests/pass/open_a_file_in_proc.stderr new file mode 100644 index 000000000000..0ba31ed5adac --- /dev/null +++ b/src/tools/miri/tests/pass/open_a_file_in_proc.stderr @@ -0,0 +1,32 @@ +warning: files in `/proc` can bypass the Abstract Machine and might not work properly in Miri + --> RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + | +LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ open a file in `/proc` + | + = note: stack backtrace: + 0: std::sys::fs::PLATFORM::File::open_c::{closure#0} + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 1: std::sys::pal::PLATFORM::cvt_r + at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + 2: std::sys::fs::PLATFORM::File::open_c + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 3: std::sys::fs::PLATFORM::File::open::{closure#0} + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 4: std::sys::helpers::small_c_string::run_with_cstr_stack + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 5: std::sys::helpers::small_c_string::run_with_cstr + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 6: std::sys::helpers::small_c_string::run_path_with_cstr + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 7: std::sys::fs::PLATFORM::File::open + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 8: std::fs::OpenOptions::_open + at RUSTLIB/std/src/fs.rs:LL:CC + 9: std::fs::OpenOptions::open + at RUSTLIB/std/src/fs.rs:LL:CC + 10: std::fs::File::open + at RUSTLIB/std/src/fs.rs:LL:CC + 11: main + at tests/pass/open_a_file_in_proc.rs:LL:CC + From 220d5142380a8c633ad829c35c045d45d27d52ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Feb 2026 12:23:30 +0100 Subject: [PATCH 06/59] clean up path check --- src/tools/miri/src/shims/unix/fs.rs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index d82a4d231315..9873af85b989 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -354,24 +354,16 @@ fn open( let this = self.eval_context_mut(); let path_raw = this.read_pointer(path_raw)?; - let path = this.read_path_from_c_str(path_raw)?; - - match path::absolute(&path) { - Ok(path) => { - // "/proc" does not work properly from inside Miri, warn about opening files there. - if matches!( - this.tcx.sess.target.os, - Os::Linux | Os::Android | Os::Illumos | Os::Solaris - ) && (path == Path::new("/proc") || path.starts_with("/proc/")) - { - this.machine.emit_diagnostic(NonHaltingDiagnostic::FileInProcOpened); - } - } - Err(_) => { /* when the path is empty, it is also unrelative to "/proc" issue */ } - } - let flag = this.read_scalar(flag)?.to_i32()?; + let path = this.read_path_from_c_str(path_raw)?; + // Files in `/proc` won't work properly. + if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android | Os::Illumos | Os::Solaris) + && path::absolute(&path).is_ok_and(|path| path.starts_with("/proc")) + { + this.machine.emit_diagnostic(NonHaltingDiagnostic::FileInProcOpened); + } + let mut options = OpenOptions::new(); let o_rdonly = this.eval_libc_i32("O_RDONLY"); From e3062fa780fefc860c1d5005b9665751c4d14283 Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 16 Feb 2026 18:24:19 +0100 Subject: [PATCH 07/59] Avoid keeping ThreadData borrowed while formatting tracing arguments Fixes RefCell being borrowed mutably twice, see https://github.com/rust-lang/miri/issues/4563#issuecomment-3415871750 . There are some places in rustc where the implementation of an argument passed to a tracing span makes a nested tracing call, e.g. [here](https://github.com/rust-lang/rust/blob/f6092f224d2b1774b31033f12d0bee626943b02f/compiler/rustc_const_eval/src/interpret/step.rs#L82-L89)->[here](https://github.com/rust-lang/rust/blob/f6092f224d2b1774b31033f12d0bee626943b02f/compiler/rustc_public/src/ty.rs#L265)->[here](https://github.com/rust-lang/rust/blob/f6092f224d2b1774b31033f12d0bee626943b02f/compiler/rustc_span/src/lib.rs#L2302). This is what caused the crash. Co-authored-by: Ralf Jung --- src/tools/miri/src/bin/log/tracing_chrome.rs | 31 ++++++++++++------- .../src/bin/log/tracing_chrome_instant.rs | 1 + 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs index 85b4de62a5ec..bfcb73ed1d76 100644 --- a/src/tools/miri/src/bin/log/tracing_chrome.rs +++ b/src/tools/miri/src/bin/log/tracing_chrome.rs @@ -53,6 +53,7 @@ use crate::log::tracing_chrome_instant::TracingChromeInstant; /// Contains thread-local data for threads that send tracing spans or events. +#[derive(Clone)] struct ThreadData { /// A unique ID for this thread, will populate "tid" field in the output trace file. tid: usize, @@ -562,15 +563,20 @@ fn exit_span(&self, span: SpanRef, ts: f64, tid: usize, out: &Sender #[inline(always)] fn with_elapsed_micros_subtracting_tracing(&self, f: impl Fn(f64, usize, &Sender)) { THREAD_DATA.with(|value| { - let mut thread_data = value.borrow_mut(); - let (ThreadData { tid, out, start }, new_thread) = match thread_data.as_mut() { - Some(thread_data) => (thread_data, false), - None => { - let tid = self.max_tid.fetch_add(1, Ordering::SeqCst); - let out = self.out.lock().unwrap().clone(); - let start = TracingChromeInstant::setup_for_thread_and_start(tid); - *thread_data = Some(ThreadData { tid, out, start }); - (thread_data.as_mut().unwrap(), true) + // Make sure not to keep `value` borrowed when calling `f` below, since the user tracing + // code that `f` might invoke (e.g. fmt::Debug argument formatting) may contain nested + // tracing calls that would cause `value` to be doubly-borrowed mutably. + let (ThreadData { tid, out, mut start }, new_thread) = { + let mut thread_data = value.borrow_mut(); + match thread_data.as_mut() { + Some(thread_data) => (thread_data.clone(), false), + None => { + let tid = self.max_tid.fetch_add(1, Ordering::SeqCst); + let out = self.out.lock().unwrap().clone(); + let start = TracingChromeInstant::setup_for_thread_and_start(tid); + *thread_data = Some(ThreadData { tid, out: out.clone(), start: start.clone() }); + (ThreadData { tid, out, start }, true) + } } }; @@ -580,10 +586,13 @@ fn with_elapsed_micros_subtracting_tracing(&self, f: impl Fn(f64, usize, &Sender Some(name) => name.to_owned(), None => tid.to_string(), }; - let _ignored = out.send(Message::NewThread(*tid, name)); + let _ignored = out.send(Message::NewThread(tid, name)); } - f(ts, *tid, out); + f(ts, tid, &out); }); + + // we have to re-borrow here, see comment above + value.borrow_mut().as_mut().unwrap().start = start; }); } } diff --git a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs index 04705b8846d9..57000b39384e 100644 --- a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs +++ b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs @@ -20,6 +20,7 @@ /// /// This measures time using [std::time::Instant], except for x86/x86_64 Linux machines, where /// [std::time::Instant] is too slow (~1.5us) and thus `rdtsc` is used instead (~5ns). +#[derive(Clone)] pub enum TracingChromeInstant { WallTime { /// The time at which this instant was created, shifted forward to account From 041e3a57a2a111604b3b4ba762fea164cb59d638 Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 16 Feb 2026 18:13:11 +0100 Subject: [PATCH 08/59] Remove RDTSC timer and always rely on Instant instead Fixes https://github.com/rust-lang/miri/issues/4563 --- src/tools/miri/src/bin/log/mod.rs | 1 - src/tools/miri/src/bin/log/tracing_chrome.rs | 44 +++-- .../src/bin/log/tracing_chrome_instant.rs | 184 ------------------ 3 files changed, 26 insertions(+), 203 deletions(-) delete mode 100644 src/tools/miri/src/bin/log/tracing_chrome_instant.rs diff --git a/src/tools/miri/src/bin/log/mod.rs b/src/tools/miri/src/bin/log/mod.rs index 22f74dd46b54..f3b2fdb5348e 100644 --- a/src/tools/miri/src/bin/log/mod.rs +++ b/src/tools/miri/src/bin/log/mod.rs @@ -1,3 +1,2 @@ pub mod setup; mod tracing_chrome; -mod tracing_chrome_instant; diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs index bfcb73ed1d76..2caea73a6e3d 100644 --- a/src/tools/miri/src/bin/log/tracing_chrome.rs +++ b/src/tools/miri/src/bin/log/tracing_chrome.rs @@ -50,8 +50,6 @@ thread::JoinHandle, }; -use crate::log::tracing_chrome_instant::TracingChromeInstant; - /// Contains thread-local data for threads that send tracing spans or events. #[derive(Clone)] struct ThreadData { @@ -62,7 +60,7 @@ struct ThreadData { out: Sender, /// The instant in time this thread was started. All events happening on this thread will be /// saved to the trace file with a timestamp (the "ts" field) measured relative to this instant. - start: TracingChromeInstant, + start: std::time::Instant, } thread_local! { @@ -566,33 +564,43 @@ fn with_elapsed_micros_subtracting_tracing(&self, f: impl Fn(f64, usize, &Sender // Make sure not to keep `value` borrowed when calling `f` below, since the user tracing // code that `f` might invoke (e.g. fmt::Debug argument formatting) may contain nested // tracing calls that would cause `value` to be doubly-borrowed mutably. - let (ThreadData { tid, out, mut start }, new_thread) = { + let (ThreadData { tid, out, start }, new_thread) = { let mut thread_data = value.borrow_mut(); match thread_data.as_mut() { Some(thread_data) => (thread_data.clone(), false), None => { let tid = self.max_tid.fetch_add(1, Ordering::SeqCst); let out = self.out.lock().unwrap().clone(); - let start = TracingChromeInstant::setup_for_thread_and_start(tid); - *thread_data = Some(ThreadData { tid, out: out.clone(), start: start.clone() }); + let start = std::time::Instant::now(); + *thread_data = Some(ThreadData { tid, out: out.clone(), start }); (ThreadData { tid, out, start }, true) } } }; - start.with_elapsed_micros_subtracting_tracing(|ts| { - if new_thread { - let name = match std::thread::current().name() { - Some(name) => name.to_owned(), - None => tid.to_string(), - }; - let _ignored = out.send(Message::NewThread(tid, name)); - } - f(ts, tid, &out); - }); + // Obtain the current time (before executing `f`). + let instant_before_f = std::time::Instant::now(); - // we have to re-borrow here, see comment above - value.borrow_mut().as_mut().unwrap().start = start; + // Using the current time (`instant_before_f`), calculate the elapsed time (in + // microseconds) since `start` was instantiated, accounting for any time that was + // previously spent executing `f`. The "accounting" part is not computed in this + // line, but is rather done by shifting forward the `start` down below. + let ts = (instant_before_f - start).as_nanos() as f64 / 1000.0; + + // Run the function (supposedly a function internal to the tracing infrastructure). + if new_thread { + let name = match std::thread::current().name() { + Some(name) => name.to_owned(), + None => tid.to_string(), + }; + let _ignored = out.send(Message::NewThread(tid, name)); + } + f(ts, tid, &out); + + // Measure how much time was spent executing `f` and shift `start` forward + // by that amount. This "removes" that time from the trace. + // See comment at the top of this function for why we have to re-borrow here. + value.borrow_mut().as_mut().unwrap().start += std::time::Instant::now() - instant_before_f; }); } } diff --git a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs deleted file mode 100644 index 57000b39384e..000000000000 --- a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Code in this class was in part inspired by -//! . -//! A useful resource is also -//! , -//! although this file does not implement TSC synchronization but instead pins threads to CPUs, -//! since the former is not reliable (i.e. it might lead to non-monotonic time measurements). -//! Another useful resource for future improvements might be measureme's time measurement utils: -//! . -//! Documentation about how the Linux kernel chooses a clock source can be found here: -//! . -#![cfg(feature = "tracing")] - -/// This alternative `TracingChromeInstant` implementation was made entirely to suit the needs of -/// [crate::log::tracing_chrome], and shouldn't be used for anything else. It features two functions: -/// - [TracingChromeInstant::setup_for_thread_and_start], which sets up the current thread to do -/// proper time tracking and returns a point in time to use as "t=0", and -/// - [TracingChromeInstant::with_elapsed_micros_subtracting_tracing], which allows -/// obtaining how much time elapsed since [TracingChromeInstant::setup_for_thread_and_start] was -/// called while accounting for (and subtracting) the time spent inside tracing-related functions. -/// -/// This measures time using [std::time::Instant], except for x86/x86_64 Linux machines, where -/// [std::time::Instant] is too slow (~1.5us) and thus `rdtsc` is used instead (~5ns). -#[derive(Clone)] -pub enum TracingChromeInstant { - WallTime { - /// The time at which this instant was created, shifted forward to account - /// for time spent in tracing functions as explained in - /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments. - start_instant: std::time::Instant, - }, - #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] - Tsc { - /// The value in the TSC counter when this instant was created, shifted forward to account - /// for time spent in tracing functions as explained in - /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments. - start_tsc: u64, - /// The period of the TSC counter in microseconds. - tsc_to_microseconds: f64, - }, -} - -impl TracingChromeInstant { - /// Can be thought of as the same as [std::time::Instant::now()], but also does some setup to - /// make TSC stable in case TSC is available. This is supposed to be called (at most) once per - /// thread since the thread setup takes a few milliseconds. - /// - /// WARNING: If TSC is available, `incremental_thread_id` is used to pick to which CPU to pin - /// the current thread. Thread IDs should be assigned contiguously starting from 0. Be aware - /// that the current thread will be restricted to one CPU for the rest of the execution! - pub fn setup_for_thread_and_start(incremental_thread_id: usize) -> TracingChromeInstant { - #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] - if *tsc::IS_TSC_AVAILABLE.get_or_init(tsc::is_tsc_available) { - // We need to lock this thread to a specific CPU, because CPUs' TSC timers might be out - // of sync. - tsc::set_cpu_affinity(incremental_thread_id); - - // Can only use tsc_to_microseconds() and rdtsc() after having set the CPU affinity! - // We compute tsc_to_microseconds anew for every new thread just in case some CPU core - // has a different TSC frequency. - let tsc_to_microseconds = tsc::tsc_to_microseconds(); - let start_tsc = tsc::rdtsc(); - return TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds }; - } - - let _ = incremental_thread_id; // otherwise we get a warning when the TSC branch is disabled - TracingChromeInstant::WallTime { start_instant: std::time::Instant::now() } - } - - /// Calls `f` with the time elapsed in microseconds since this [TracingChromeInstant] was built - /// by [TracingChromeInstant::setup_for_thread_and_start], while subtracting all time previously - /// spent executing other `f`s passed to this function. This behavior allows subtracting time - /// spent in functions that log tracing data (which `f` is supposed to be) from the tracing time - /// measurements. - /// - /// Note: microseconds are used as the time unit since that's what Chrome trace files should - /// contain, see the definition of the "ts" field in - /// . - #[inline(always)] - pub fn with_elapsed_micros_subtracting_tracing(&mut self, f: impl Fn(f64)) { - match self { - TracingChromeInstant::WallTime { start_instant } => { - // Obtain the current time (before executing `f`). - let instant_before_f = std::time::Instant::now(); - - // Using the current time (`instant_before_f`) and the `start_instant` stored in - // `self`, calculate the elapsed time (in microseconds) since this instant was - // instantiated, accounting for any time that was previously spent executing `f`. - // The "accounting" part is not computed in this line, but is rather done by - // shifting forward the `start_instant` down below. - let ts = (instant_before_f - *start_instant).as_nanos() as f64 / 1000.0; - - // Run the function (supposedly a function internal to the tracing infrastructure). - f(ts); - - // Measure how much time was spent executing `f` and shift `start_instant` forward - // by that amount. This "removes" that time from the trace. - *start_instant += std::time::Instant::now() - instant_before_f; - } - - #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] - TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds } => { - // the comments above also apply here, since it's the same logic - let tsc_before_f = tsc::rdtsc(); - let ts = ((tsc_before_f - *start_tsc) as f64) * (*tsc_to_microseconds); - f(ts); - *start_tsc += tsc::rdtsc() - tsc_before_f; - } - } - } -} - -#[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] -mod tsc { - - pub static IS_TSC_AVAILABLE: std::sync::OnceLock = std::sync::OnceLock::new(); - - /// Reads the timestamp-counter register. Will give monotonic answers only when called from the - /// same thread, because the TSC of different CPUs might be out of sync. - #[inline(always)] - pub(super) fn rdtsc() -> u64 { - #[cfg(target_arch = "x86")] - use core::arch::x86::_rdtsc; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::_rdtsc; - - unsafe { _rdtsc() } - } - - /// Estimates the frequency of the TSC counter by waiting 10ms in a busy loop and - /// looking at how much the TSC increased in the meantime. - pub(super) fn tsc_to_microseconds() -> f64 { - const BUSY_WAIT: std::time::Duration = std::time::Duration::from_millis(10); - let tsc_start = rdtsc(); - let instant_start = std::time::Instant::now(); - while instant_start.elapsed() < BUSY_WAIT { - // `thread::sleep()` is not very precise at waking up the program at the right time, - // so use a busy loop instead. - core::hint::spin_loop(); - } - let tsc_end = rdtsc(); - (BUSY_WAIT.as_nanos() as f64) / 1000.0 / ((tsc_end - tsc_start) as f64) - } - - /// Checks whether the TSC counter is available and runs at a constant rate independently - /// of CPU frequency even across different power states of the CPU (i.e. checks for the - /// `invariant_tsc` CPUID flag). - pub(super) fn is_tsc_available() -> bool { - #[cfg(target_arch = "x86")] - use core::arch::x86::__cpuid; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::__cpuid; - - // implemented like https://docs.rs/raw-cpuid/latest/src/raw_cpuid/extended.rs.html#965-967 - const LEAF: u32 = 0x80000007; // this is the leaf for "advanced power management info" - let cpuid = __cpuid(LEAF); - (cpuid.edx & (1 << 8)) != 0 // EDX bit 8 indicates invariant TSC - } - - /// Forces the current thread to run on a single CPU, which ensures the TSC counter is monotonic - /// (since TSCs of different CPUs might be out-of-sync). `incremental_thread_id` is used to pick - /// to which CPU to pin the current thread, and should be an incremental number that starts from - /// 0. - pub(super) fn set_cpu_affinity(incremental_thread_id: usize) { - let cpu_id = match std::thread::available_parallelism() { - Ok(available_parallelism) => incremental_thread_id % available_parallelism, - _ => panic!("Could not determine CPU count to properly set CPU affinity"), - }; - - let mut set = unsafe { std::mem::zeroed::() }; - unsafe { libc::CPU_SET(cpu_id, &mut set) }; - - // Set the current thread's core affinity. - if unsafe { - libc::sched_setaffinity( - 0, // Defaults to current thread - size_of::(), - &set as *const _, - ) - } != 0 - { - panic!("Could not set CPU affinity") - } - } -} From b0b2e8c6cde5a11d7bd7aa2e564806606df29ed2 Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 16 Feb 2026 18:41:12 +0100 Subject: [PATCH 09/59] Update documentation for tracing --- src/tools/miri/CONTRIBUTING.md | 2 ++ src/tools/miri/doc/tracing.md | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index f9cb60c66d91..852ea26ab89e 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -189,6 +189,8 @@ you can visualize in [Perfetto](https://ui.perfetto.dev/). For example: MIRI_TRACING=1 ./miri run --features=tracing tests/pass/hello.rs ``` +See [doc/tracing.md](./doc/tracing.md) for more information. + ### UI testing We use ui-testing in Miri, meaning we generate `.stderr` and `.stdout` files for the output diff --git a/src/tools/miri/doc/tracing.md b/src/tools/miri/doc/tracing.md index d7114af947dc..1208ca8d6ec7 100644 --- a/src/tools/miri/doc/tracing.md +++ b/src/tools/miri/doc/tracing.md @@ -2,6 +2,9 @@ Miri can be traced to understand how much time is spent in its various components (e.g. borrow tracker, data race checker, etc.). When tracing is enabled, running Miri will create a `.json` trace file that can be opened and analyzed in [Perfetto](https://ui.perfetto.dev/). For any questions regarding this documentation you may contact [Stypox](https://rust-lang.zulipchat.com/#narrow/dm/627563-Stypox) on Zulip. +> [!WARNING] +> Tracing in Miri at the moment is broken due to two bugs in tracing libraries: https://github.com/tokio-rs/tracing/pull/3392 and https://github.com/davidbarsky/tracing-tree/issues/93. Also see https://github.com/rust-lang/miri/issues/4752. + ## Obtaining a trace file ### From the Miri codebase @@ -277,9 +280,12 @@ So the solution was to copy-paste [the only file](https://github.com/thoren-d/tr ### Time measurements -tracing-chrome originally used `std::time::Instant` to measure time, however on some x86/x86_64 Linux systems it might be unbearably slow since the underlying system call (`clock_gettime`) would take ≈1.3µs. Read more [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) about how the Linux kernel chooses the clock source. +tracing-chrome uses `std::time::Instant` to measure time. On most modern systems this is ok, since the underlying system call (`clock_gettime`) uses very fast hardware counters (e.g. `tsc`) and has a latency of ≈16ns. -Therefore, on x86/x86_64 Linux systems with a CPU that has an invariant TSC counter, we read from that instead to measure time, which takes only ≈13ns. There are unfortunately a lot of caveats to this approach though, as explained [in the code](https://github.com/rust-lang/miri/blob/master/src/bin/log/tracing_chrome_instant.rs) and [in the PR](https://github.com/rust-lang/miri/pull/4524). The most impactful one is that: every thread spawned in Miri that wants to trace something (which requires measuring time) needs to pin itself to a single CPU core (using `sched_setaffinity`). +On some x86/x86_64 Linux systems, however, `tsc` is not "reliable" and the system thus relies on other timers, e.g. `hpet` which takes ≈1.3µs. Read [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) how the Linux kernel chooses the clock source, and how to check if your system is using `tsc`. If it doesn't use `tsc`, then expect most of the trace time being spent in time measurements, which degrades traces' usefulness... See [here](https://github.com/rust-lang/miri/issues/4563) for some discussion. + +> [!WARNING] +> A (somewhat risky) workaround is to add `tsc=reliable clocksource=tsc hpet=disable` to the kernel boot parameters, which forces it to use `tsc` even if it is unreliable. But this may render the system unstable, so try it at your own risk! ## Other useful stuff From 7be626903c786021ed1bf50b5601758714e6f5c4 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sat, 21 Feb 2026 22:32:24 -0500 Subject: [PATCH 10/59] Fix typo in tracing.md for `tracing_separate_thread` Remove duplicate "the" in documentation. --- src/tools/miri/doc/tracing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/doc/tracing.md b/src/tools/miri/doc/tracing.md index 1208ca8d6ec7..1fbdd945d977 100644 --- a/src/tools/miri/doc/tracing.md +++ b/src/tools/miri/doc/tracing.md @@ -243,7 +243,7 @@ let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_p ### `tracing_separate_thread` parameter -Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example: +Miri saves traces using the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example: ```rust let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty); ``` From 4a2f129022035bd99d54d978b31b2e4fb35e1c8a Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 22 Feb 2026 05:16:15 +0000 Subject: [PATCH 11/59] Prepare for merging from rust-lang/rust This updates the rust-version file to 5fb2ff8611e5a4af4dc85977cfdecfbf3ffa6ade. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index befd6c8a9196..379f038b6d1c 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -e0cb264b814526acb82def4b5810e394a2ed294f +5fb2ff8611e5a4af4dc85977cfdecfbf3ffa6ade From 3607191d85628251e5c02f65326a7f4fd17ae488 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Feb 2026 13:36:12 +0100 Subject: [PATCH 12/59] register Miri-specific symbols with the interner --- src/tools/miri/src/bin/miri.rs | 7 ++++ .../miri/src/concurrency/genmc/scheduling.rs | 9 ++--- src/tools/miri/src/concurrency/genmc/shims.rs | 1 - src/tools/miri/src/intrinsics/mod.rs | 2 +- src/tools/miri/src/lib.rs | 2 ++ src/tools/miri/src/sym.rs | 36 +++++++++++++++++++ 6 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 src/tools/miri/src/sym.rs diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 14528759472c..3766debb159d 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -193,7 +193,11 @@ fn make_miri_codegen_backend(opts: &Options, target: &Target) -> Box( @@ -354,6 +358,9 @@ fn config(&mut self, config: &mut Config) { ) } }); + + // Register our custom extra symbols. + config.extra_symbols = miri::sym::EXTRA_SYMBOLS.into(); } fn after_analysis<'tcx>( diff --git a/src/tools/miri/src/concurrency/genmc/scheduling.rs b/src/tools/miri/src/concurrency/genmc/scheduling.rs index c760126d787d..54e87c05818d 100644 --- a/src/tools/miri/src/concurrency/genmc/scheduling.rs +++ b/src/tools/miri/src/concurrency/genmc/scheduling.rs @@ -5,7 +5,8 @@ use super::GenmcCtx; use crate::{ - InterpCx, InterpResult, MiriMachine, TerminationInfo, ThreadId, interp_ok, throw_machine_stop, + InterpCx, InterpResult, MiriMachine, TerminationInfo, ThreadId, interp_ok, sym, + throw_machine_stop, }; enum NextInstrKind { @@ -76,11 +77,11 @@ fn get_function_kind<'tcx>( // NOTE: Functions intercepted by Miri in `concurrency/genmc/intercep.rs` must also be added here. // Such intercepted functions, like `sys::Mutex::lock`, should be treated as atomics to ensure we call the scheduler when we encounter one of them. // These functions must also be classified whether they may have load semantics. - if ecx.tcx.is_diagnostic_item(rustc_span::sym::sys_mutex_lock, callee_def_id) - || ecx.tcx.is_diagnostic_item(rustc_span::sym::sys_mutex_try_lock, callee_def_id) + if ecx.tcx.is_diagnostic_item(sym::sys_mutex_lock, callee_def_id) + || ecx.tcx.is_diagnostic_item(sym::sys_mutex_try_lock, callee_def_id) { return interp_ok(MaybeAtomic(ActionKind::Load)); - } else if ecx.tcx.is_diagnostic_item(rustc_span::sym::sys_mutex_unlock, callee_def_id) { + } else if ecx.tcx.is_diagnostic_item(sym::sys_mutex_unlock, callee_def_id) { return interp_ok(MaybeAtomic(ActionKind::NonLoad)); } // The next step is a call to a regular Rust function. diff --git a/src/tools/miri/src/concurrency/genmc/shims.rs b/src/tools/miri/src/concurrency/genmc/shims.rs index cac03a21afc5..ff9d43e70a46 100644 --- a/src/tools/miri/src/concurrency/genmc/shims.rs +++ b/src/tools/miri/src/concurrency/genmc/shims.rs @@ -198,7 +198,6 @@ fn genmc_intercept_function( ); // NOTE: When adding new intercepted functions here, they must also be added to `fn get_function_kind` in `concurrency/genmc/scheduling.rs`. - use rustc_span::sym; if this.tcx.is_diagnostic_item(sym::sys_mutex_lock, instance.def_id()) { let [mutex] = get_fn_args(instance, args)?; let mutex = this.deref_pointer(&mutex)?; diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index f09fc6c18789..ae7ec1fdcce5 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -10,7 +10,7 @@ use rand::Rng; use rustc_abi::Size; use rustc_middle::{mir, ty}; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use self::atomic::EvalContextExt as _; use self::math::EvalContextExt as _; diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 232a24306d65..1bfc0cceafb8 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -17,6 +17,7 @@ #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] #![feature(iter_advance_by)] +#![feature(macro_metavar_expr)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -87,6 +88,7 @@ mod operator; mod provenance_gc; mod shims; +pub mod sym; // Establish a "crate-wide prelude": we often import `crate::*`. // Make all those symbols available in the same place as our own. diff --git a/src/tools/miri/src/sym.rs b/src/tools/miri/src/sym.rs new file mode 100644 index 000000000000..7c870494f216 --- /dev/null +++ b/src/tools/miri/src/sym.rs @@ -0,0 +1,36 @@ +#![allow(non_upper_case_globals)] + +#[doc(no_inline)] +pub use rustc_span::sym::*; + +macro_rules! val { + ($name:ident) => { + stringify!($name) + }; + ($name:ident $value:literal) => { + $value + }; +} + +macro_rules! generate { + ($($name:ident $(: $value:literal)? ,)*) => { + /// To be supplied to `rustc_interface::Config` + pub const EXTRA_SYMBOLS: &[&str] = &[ + $( + val!($name $($value)?), + )* + ]; + + $( + pub const $name: rustc_span::Symbol = rustc_span::Symbol::new(rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT + ${index()}); + )* + }; +} + +// List of extra symbols to be included in Miri. +// An alternative content can be specified using a colon after the symbol name. +generate! { + sys_mutex_lock, + sys_mutex_try_lock, + sys_mutex_unlock, +} From e7e512da465d520ac084f5f4fa235210debf5296 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 23 Feb 2026 05:22:16 +0000 Subject: [PATCH 13/59] Prepare for merging from rust-lang/rust This updates the rust-version file to c78a29473a68f07012904af11c92ecffa68fcc75. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 379f038b6d1c..b6e1b2bc55df 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5fb2ff8611e5a4af4dc85977cfdecfbf3ffa6ade +c78a29473a68f07012904af11c92ecffa68fcc75 From 7ed7b2b820c16789955a5d9936ad23bc62a1ab4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Feb 2026 09:11:58 +0100 Subject: [PATCH 14/59] Prepare for merging from rust-lang/rust This updates the rust-version file to b3869b94cd1ed4bfa2eb28f301535d5e9599c713. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index b6e1b2bc55df..bef3f42f7775 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -c78a29473a68f07012904af11c92ecffa68fcc75 +b3869b94cd1ed4bfa2eb28f301535d5e9599c713 From 2e17c9b81a0446cdfaae88e038bbfbba7d105b5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Feb 2026 22:29:26 +0100 Subject: [PATCH 15/59] remove FIXME about size of Pointer type --- src/tools/miri/src/machine.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 7883673cdd6a..000f4ac4ceca 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -300,7 +300,8 @@ pub enum ProvenanceExtra { #[cfg(target_pointer_width = "64")] static_assert_size!(StrictPointer, 24); -// FIXME: this would with in 24bytes but layout optimizations are not smart enough +// Pointer does not fit as the layout algorithm isn't smart enough (but also, we tried using +// pattern types to get a larger niche that makes this fit and it didn't improve performance). // #[cfg(target_pointer_width = "64")] //static_assert_size!(Pointer, 24); #[cfg(target_pointer_width = "64")] From d398074f2293b166b07e63fd7f090f912c22ac64 Mon Sep 17 00:00:00 2001 From: WhySoBad <49595640+WhySoBad@users.noreply.github.com> Date: Sun, 22 Feb 2026 01:21:00 +0100 Subject: [PATCH 16/59] Start socket shim Basic shim which allows opening and closing a socket --- .../miri/src/shims/unix/foreign_items.rs | 12 ++ src/tools/miri/src/shims/unix/mod.rs | 2 + src/tools/miri/src/shims/unix/socket.rs | 157 ++++++++++++++++++ .../libc/libc-socket-with-isolation.rs | 19 +++ .../libc/libc-socket-with-isolation.stderr | 2 + .../miri/tests/pass-dep/libc/libc-socket.rs | 19 +++ 6 files changed, 211 insertions(+) create mode 100644 src/tools/miri/src/shims/unix/socket.rs create mode 100644 src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs create mode 100644 src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.stderr create mode 100644 src/tools/miri/tests/pass-dep/libc/libc-socket.rs diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 48e2ebd0f13e..130643ec680d 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -539,6 +539,18 @@ fn emulate_foreign_item_inner( this.write_scalar(result, dest)?; } + // Network sockets + "socket" => { + let [domain, type_, protocol] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, i32, i32) -> i32), + link_name, + abi, + args, + )?; + let result = this.socket(domain, type_, protocol)?; + this.write_scalar(result, dest)?; + } + // Time "gettimeofday" => { let [tv, tz] = this.check_shim_sig( diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 660e4ded5cda..5ea49926fb9f 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -4,6 +4,7 @@ mod fd; mod fs; mod mem; +mod socket; mod sync; mod thread; mod unnamed_socket; @@ -21,6 +22,7 @@ pub use self::fs::{DirTable, EvalContextExt as _}; pub use self::linux_like::epoll::EpollInterestTable; pub use self::mem::EvalContextExt as _; +pub use self::socket::EvalContextExt as _; pub use self::sync::EvalContextExt as _; pub use self::thread::{EvalContextExt as _, ThreadNameResult}; pub use self::unnamed_socket::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs new file mode 100644 index 000000000000..66fe5d8a44a4 --- /dev/null +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -0,0 +1,157 @@ +use std::cell::Cell; +use std::net::{TcpListener, TcpStream}; + +use rustc_const_eval::interpret::{InterpResult, interp_ok}; +use rustc_middle::throw_unsup_format; +use rustc_target::spec::Os; + +use crate::shims::files::{FdId, FileDescription}; +use crate::{OpTy, Scalar, *}; + +#[derive(Debug, PartialEq)] +enum SocketFamily { + // IPv4 internet protocols + IPv4, + // IPv6 internet protocols + IPv6, +} + +#[derive(Debug)] +enum SocketType { + /// Reliable full-duplex communication, based on connections. + Stream, +} + +#[allow(unused)] +#[derive(Debug)] +enum SocketKind { + TcpListener(TcpListener), + TcpStream(TcpStream), +} + +#[allow(unused)] +#[derive(Debug)] +struct Socket { + /// Family of the socket, used to ensure socket only binds/connects to address of + /// same family. + family: SocketFamily, + /// Type of the socket, either datagram or stream. + /// Only stream is supported at the moment! + socket_type: SocketType, + /// Whether this fd is non-blocking or not. + is_non_block: Cell, +} + +impl FileDescription for Socket { + fn name(&self) -> &'static str { + "socket" + } + + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, std::io::Result<()>> + where + Self: Sized, + { + interp_ok(Ok(())) + } + + fn get_flags<'tcx>(&self, ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, Scalar> { + let mut flags = ecx.eval_libc_i32("O_RDWR"); + + if self.is_non_block.get() { + flags |= ecx.eval_libc_i32("O_NONBLOCK"); + } + + interp_ok(Scalar::from_i32(flags)) + } + + fn set_flags<'tcx>( + &self, + mut _flag: i32, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + throw_unsup_format!("fcntl: socket flags aren't supported") + } +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// For more information on the arguments see the socket manpage: + /// + fn socket( + &mut self, + domain: &OpTy<'tcx>, + type_: &OpTy<'tcx>, + protocol: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let domain = this.read_scalar(domain)?.to_i32()?; + let mut flags = this.read_scalar(type_)?.to_i32()?; + let protocol = this.read_scalar(protocol)?.to_i32()?; + + // Reject if isolation is enabled + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`socket`", reject_with)?; + this.set_last_error(LibcError("EACCES"))?; + return interp_ok(Scalar::from_i32(-1)); + } + + let mut is_sock_nonblock = false; + + // Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so + // if there is anything left at the end, that's an unsupported flag. + if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android | Os::FreeBsd) { + // SOCK_NONBLOCK and SOCK_CLOEXEC only exist on Linux, Android and FreeBSD. + let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK"); + let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC"); + if flags & sock_nonblock == sock_nonblock { + is_sock_nonblock = true; + flags &= !sock_nonblock; + } + if flags & sock_cloexec == sock_cloexec { + // We don't support `exec` so we can ignore this. + flags &= !sock_cloexec; + } + } + + let family = if domain == this.eval_libc_i32("AF_INET") { + SocketFamily::IPv4 + } else if domain == this.eval_libc_i32("AF_INET6") { + SocketFamily::IPv6 + } else { + throw_unsup_format!( + "socket: domain {:#x} is unsupported, only AF_INET and \ + AF_INET6 are allowed.", + domain + ); + }; + + if flags != this.eval_libc_i32("SOCK_STREAM") { + throw_unsup_format!( + "socket: type {:#x} is unsupported, only SOCK_STREAM, \ + SOCK_CLOEXEC and SOCK_NONBLOCK are allowed", + flags + ); + } + if protocol != 0 { + throw_unsup_format!( + "socket: socket protocol {protocol} is unsupported, \ + only 0 is allowed" + ); + } + + let fds = &mut this.machine.fds; + let fd = fds.new_ref(Socket { + family, + is_non_block: Cell::new(is_sock_nonblock), + socket_type: SocketType::Stream, + }); + + interp_ok(Scalar::from_i32(fds.insert(fd))) + } +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs new file mode 100644 index 000000000000..ce4df4de72b6 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs @@ -0,0 +1,19 @@ +//@ignore-target: windows # No libc socket on Windows +//@ignore-target: solaris # Socket is a macro for __xnet7_socket which has no shim +//@ignore-target: illumos # Socket is a macro for __xnet7_socket which has no shim +//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace + +use std::io::ErrorKind; + +#[path = "../../utils/libc.rs"] +mod libc_utils; +use libc_utils::*; + +fn main() { + unsafe { + let err = errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap_err(); + assert_eq!(err.kind(), ErrorKind::PermissionDenied); + // check that it is the right kind of `PermissionDenied` + assert_eq!(err.raw_os_error(), Some(libc::EACCES)); + } +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.stderr b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.stderr new file mode 100644 index 000000000000..36fc0a5aac32 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.stderr @@ -0,0 +1,2 @@ +warning: `socket` was made to return an error due to isolation + diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket.rs b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs new file mode 100644 index 000000000000..ac9f13367642 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs @@ -0,0 +1,19 @@ +//@ignore-target: windows # No libc socket on Windows +//@ignore-target: solaris # Does socket is a macro for __xnet7_socket which has no shim +//@ignore-target: illumos # Does socket is a macro for __xnet7_socket which has no shim +//@compile-flags: -Zmiri-disable-isolation + +#[path = "../../utils/libc.rs"] +mod libc_utils; +use libc_utils::*; + +fn main() { + test_socket_close(); +} + +fn test_socket_close() { + unsafe { + let sockfd = errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap(); + errno_check(libc::close(sockfd)); + } +} From 6d271ba50557a3ea5065fb0ef72d02274cf65c74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Feb 2026 18:00:37 +0100 Subject: [PATCH 17/59] Prepare for merging from rust-lang/rust This updates the rust-version file to bb779a91568ac1ee0b8a9dcb6b69219ef30b18a3. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index bef3f42f7775..4e570e369316 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -b3869b94cd1ed4bfa2eb28f301535d5e9599c713 +bb779a91568ac1ee0b8a9dcb6b69219ef30b18a3 From 470706d13fe7da769185868f78d32ce9264afcbf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Feb 2026 19:10:26 +0100 Subject: [PATCH 18/59] silence clippy lint that makes code harder to read --- src/tools/miri/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 176d4976cec6..5787efdf8cd1 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -40,6 +40,7 @@ clippy::needless_lifetimes, clippy::too_long_first_doc_paragraph, clippy::len_zero, + clippy::collapsible_match, // We are not implementing queries here so it's fine rustc::potential_query_instability, )] From b8d5538f51c278ca19f9c3e83ad44275d32492ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Feb 2026 19:20:46 +0100 Subject: [PATCH 19/59] add test for deallocating partially-interior-mutable ref --- .../both_borrows/mixed_cell_deallocate.rs | 18 ++++++++++++++ .../mixed_cell_deallocate.stack.stderr | 23 ++++++++++++++++++ .../mixed_cell_deallocate.tree.stderr | 24 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.rs create mode 100644 src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.stack.stderr create mode 100644 src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.tree.stderr diff --git a/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.rs b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.rs new file mode 100644 index 000000000000..73776827aec0 --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.rs @@ -0,0 +1,18 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + +use std::alloc; +use std::cell::Cell; + +type T = (Cell, i32); + +// Deallocating `x` is UB because not all bytes are in an `UnsafeCell`. +fn foo(x: &T) { + let layout = alloc::Layout::new::(); + unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; //~ERROR: dealloc +} + +fn main() { + let b: Box = Box::new((Cell::new(0), 0)); + foo(unsafe { std::mem::transmute(Box::into_raw(b)) }); +} diff --git a/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.stack.stderr b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.stack.stderr new file mode 100644 index 000000000000..ae99f17fd9c2 --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.stack.stderr @@ -0,0 +1,23 @@ +error: Undefined Behavior: attempting deallocation using at ALLOC, but that tag only grants SharedReadOnly permission for this location + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a SharedReadOnly retag at offsets [0x4..0xc] + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; + | ^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + 1: main + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.tree.stderr new file mode 100644 index 000000000000..5dc2ffc27c1c --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.tree.stderr @@ -0,0 +1,24 @@ +error: Undefined Behavior: deallocation through at ALLOC[0x4] is forbidden + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Frozen which forbids this deallocation (acting as a child write access) +help: the accessed tag was created here, in the initial state Cell + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | fn foo(x: &T) { + | ^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + 1: main + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From dda4f84c5661608f012c50f9b6d403ab1581c31f Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Sat, 28 Feb 2026 00:59:24 +0000 Subject: [PATCH 20/59] Add `#[must_use]` attribute to `HashMap` and `HashSet` constructors --- library/alloc/src/collections/btree/map.rs | 1 + library/alloc/src/collections/btree/set.rs | 1 + library/std/src/collections/hash/map.rs | 4 ++++ library/std/src/collections/hash/set.rs | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index d69dad70a44e..fdeb9e332c7e 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -693,6 +693,7 @@ pub fn clear(&mut self) { /// map.insert(1, "a"); /// ``` #[unstable(feature = "btreemap_alloc", issue = "32838")] + #[must_use] pub const fn new_in(alloc: A) -> BTreeMap { BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc), _marker: PhantomData } } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index fd27e87b1f47..af6f5c7d7017 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -361,6 +361,7 @@ impl BTreeSet { /// let mut set: BTreeSet = BTreeSet::new_in(Global); /// ``` #[unstable(feature = "btreemap_alloc", issue = "32838")] + #[must_use] pub const fn new_in(alloc: A) -> BTreeSet { BTreeSet { map: BTreeMap::new_in(alloc) } } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index b82beb3b8b2e..fe49660325e6 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -357,6 +357,7 @@ impl HashMap { /// map.insert(1, 2); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hash_builder: S) -> HashMap { @@ -389,6 +390,7 @@ pub const fn with_hasher(hash_builder: S) -> HashMap { /// map.insert(1, 2); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap { HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) } @@ -409,6 +411,7 @@ impl HashMap { /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the `HashMap` to be useful, see its documentation for details. #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { HashMap { base: base::HashMap::with_hasher_in(hash_builder, alloc) } @@ -430,6 +433,7 @@ pub fn with_hasher_in(hash_builder: S, alloc: A) -> Self { /// the `HashMap` to be useful, see its documentation for details. /// #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { HashMap { base: base::HashMap::with_capacity_and_hasher_in(capacity, hash_builder, alloc) } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 3f3d601e4d30..0fe26848fe7b 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -229,6 +229,7 @@ impl HashSet { /// set.insert(2); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] #[rustc_const_stable(feature = "const_collections_with_hasher", since = "1.85.0")] pub const fn with_hasher(hasher: S) -> HashSet { @@ -261,6 +262,7 @@ pub const fn with_hasher(hasher: S) -> HashSet { /// set.insert(1); /// ``` #[inline] + #[must_use] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } @@ -281,6 +283,7 @@ impl HashSet { /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the `HashSet` to be useful, see its documentation for details. #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet { HashSet { base: base::HashSet::with_hasher_in(hasher, alloc) } @@ -301,6 +304,7 @@ pub fn with_hasher_in(hasher: S, alloc: A) -> HashSet { /// The `hash_builder` passed should implement the [`BuildHasher`] trait for /// the `HashSet` to be useful, see its documentation for details. #[inline] + #[must_use] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> HashSet { HashSet { base: base::HashSet::with_capacity_and_hasher_in(capacity, hasher, alloc) } From 7b8534e0111661602ade251f3c5362235d9d4863 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Feb 2026 16:52:38 +0100 Subject: [PATCH 21/59] Prepare for merging from rust-lang/rust This updates the rust-version file to ba1567989ee7774a1fb53aa680a8e4e8daa0f519. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 4e570e369316..3e265317484a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -bb779a91568ac1ee0b8a9dcb6b69219ef30b18a3 +ba1567989ee7774a1fb53aa680a8e4e8daa0f519 From a49c0837a63fb13bc2a330dcf30c6b6abff39c1c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2026 12:38:43 +0100 Subject: [PATCH 22/59] native-lib: better organize fn ptr tests --- ...r.notrace.stderr => call_fn_ptr.notrace.stderr} | 12 ++++++------ .../fail/{call_function_ptr.rs => call_fn_ptr.rs} | 0 ...n_ptr.trace.stderr => call_fn_ptr.trace.stderr} | 12 ++++++------ src/tools/miri/tests/native-lib/fn_ptr.c | 11 +++++++++++ .../miri/tests/native-lib/pass/ptr_read_access.rs | 14 -------------- src/tools/miri/tests/native-lib/ptr_read_access.c | 13 ------------- src/tools/miri/tests/ui.rs | 3 ++- 7 files changed, 25 insertions(+), 40 deletions(-) rename src/tools/miri/tests/native-lib/fail/{call_function_ptr.notrace.stderr => call_fn_ptr.notrace.stderr} (77%) rename src/tools/miri/tests/native-lib/fail/{call_function_ptr.rs => call_fn_ptr.rs} (100%) rename src/tools/miri/tests/native-lib/fail/{call_function_ptr.trace.stderr => call_fn_ptr.trace.stderr} (79%) create mode 100644 src/tools/miri/tests/native-lib/fn_ptr.c diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.notrace.stderr similarity index 77% rename from src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr rename to src/tools/miri/tests/native-lib/fail/call_fn_ptr.notrace.stderr index faabba9ca725..5e7764652fa7 100644 --- a/src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.notrace.stderr @@ -1,5 +1,5 @@ warning: sharing memory with a native function called via FFI - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function @@ -10,12 +10,12 @@ LL | call_fn_ptr(Some(nop)); = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC error: unsupported operation: calling a function pointer through the FFI boundary - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here @@ -23,9 +23,9 @@ LL | call_fn_ptr(Some(nop)); = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.rs b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.rs similarity index 100% rename from src/tools/miri/tests/native-lib/fail/call_function_ptr.rs rename to src/tools/miri/tests/native-lib/fail/call_fn_ptr.rs diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.trace.stderr similarity index 79% rename from src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr rename to src/tools/miri/tests/native-lib/fail/call_fn_ptr.trace.stderr index e56a5ece782b..7418b08ebe11 100644 --- a/src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.trace.stderr @@ -1,5 +1,5 @@ warning: sharing memory with a native function called via FFI - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function @@ -11,12 +11,12 @@ LL | call_fn_ptr(Some(nop)); = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC error: unsupported operation: calling a function pointer through the FFI boundary - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here @@ -24,9 +24,9 @@ LL | call_fn_ptr(Some(nop)); = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/fn_ptr.c b/src/tools/miri/tests/native-lib/fn_ptr.c new file mode 100644 index 000000000000..99eb8d458c2d --- /dev/null +++ b/src/tools/miri/tests/native-lib/fn_ptr.c @@ -0,0 +1,11 @@ +#include +#include + +// See comments in build_native_lib() +#define EXPORT __attribute__((visibility("default"))) + +EXPORT void call_fn_ptr(void f(void)) { + if (f != NULL) { + f(); + } +} diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs index 36eff04a03c0..ad4c84d3e83b 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs @@ -10,7 +10,6 @@ fn main() { test_access_simple(); test_access_nested(); test_access_static(); - pass_fn_ptr(); } /// Test function that dereferences an int pointer and prints its contents from C. @@ -82,16 +81,3 @@ struct Static { assert_eq!(unsafe { access_static(&STATIC) }, 9001); } - -fn pass_fn_ptr() { - extern "C" { - fn pass_fn_ptr(s: Option); - } - - extern "C" fn nop() {} - - unsafe { - pass_fn_ptr(None); // this one is fine - pass_fn_ptr(Some(nop)); // this one is not - } -} diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c index 44ba13aa54a6..58017d809af8 100644 --- a/src/tools/miri/tests/native-lib/ptr_read_access.c +++ b/src/tools/miri/tests/native-lib/ptr_read_access.c @@ -62,16 +62,3 @@ EXPORT int32_t access_static(const Static *s_ptr) { EXPORT uintptr_t do_one_deref(const int32_t ***ptr) { return (uintptr_t)*ptr; } - -/* Test: pass_fn_ptr */ - -EXPORT void pass_fn_ptr(void f(void)) { - (void)f; // suppress unused warning -} - -/* Test: function_ptrs */ -EXPORT void call_fn_ptr(void f(void)) { - if (f != NULL) { - f(); - } -} diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index 047cdeb357c2..2a6151737d6c 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -42,7 +42,7 @@ fn build_native_lib(target: &str) -> PathBuf { std::fs::create_dir_all(&so_target_dir) .expect("Failed to create directory for shared object file"); // We use a platform-neutral file extension to avoid having to hard-code alternatives. - let native_lib_path = so_target_dir.join("native-lib.module"); + let native_lib_path = so_target_dir.join("native-lib-tests.so"); let cc_output = Command::new(cc) .args([ "-shared", @@ -58,6 +58,7 @@ fn build_native_lib(target: &str) -> PathBuf { "tests/native-lib/aggregate_arguments.c", "tests/native-lib/ptr_read_access.c", "tests/native-lib/ptr_write_access.c", + "tests/native-lib/fn_ptr.c", // Ensure we notice serious problems in the C code. "-Wall", "-Wextra", From 71f4b75236c6137da231d510e212203253d65e2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2026 12:46:32 +0100 Subject: [PATCH 23/59] native-lib: also test fn ptrs that are instances of generics --- src/tools/miri/src/alloc_addresses/mod.rs | 6 +++- .../call_fn_ptr_with_generic.notrace.stderr | 31 ++++++++++++++++++ .../fail/call_fn_ptr_with_generic.rs | 22 +++++++++++++ .../call_fn_ptr_with_generic.trace.stderr | 32 +++++++++++++++++++ src/tools/miri/tests/native-lib/fn_ptr.c | 6 ++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.notrace.stderr create mode 100644 src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs create mode 100644 src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.trace.stderr diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 32897eb89a83..91559e76e68c 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -168,7 +168,11 @@ fn addr_from_alloc_id_uncached( if let Some(GlobalAlloc::Function { instance, .. }) = this.tcx.try_get_global_alloc(alloc_id) { - let fn_sig = this.tcx.fn_sig(instance.def_id()).skip_binder().skip_binder(); + let fn_sig = this.tcx.instantiate_bound_regions_with_erased( + this.tcx + .fn_sig(instance.def_id()) + .instantiate(*this.tcx, instance.args), + ); let fn_ptr = crate::shims::native_lib::build_libffi_closure(this, fn_sig)?; #[expect( diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.notrace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.notrace.stderr new file mode 100644 index 000000000000..e0536a4afe58 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.notrace.stderr @@ -0,0 +1,31 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory + = help: in particular, Miri assumes that the native call initializes all memory it has access to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +error: unsupported operation: calling a function pointer through the FFI boundary + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs new file mode 100644 index 000000000000..8be29c0c121a --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs @@ -0,0 +1,22 @@ +//@revisions: trace notrace +//@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + pass_fn_ptr() +} + +fn pass_fn_ptr() { + extern "C" { + fn call_fn_ptr(s: extern "C" fn(i32) -> i32); + } + + extern "C" fn id(x: T) -> T { + x + } + + unsafe { + call_fn_ptr(id::); //~ ERROR: unsupported operation: calling a function pointer through the FFI boundary + } +} diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.trace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.trace.stderr new file mode 100644 index 000000000000..24a33e645868 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.trace.stderr @@ -0,0 +1,32 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +error: unsupported operation: calling a function pointer through the FFI boundary + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + diff --git a/src/tools/miri/tests/native-lib/fn_ptr.c b/src/tools/miri/tests/native-lib/fn_ptr.c index 99eb8d458c2d..752e27b3e8a0 100644 --- a/src/tools/miri/tests/native-lib/fn_ptr.c +++ b/src/tools/miri/tests/native-lib/fn_ptr.c @@ -9,3 +9,9 @@ EXPORT void call_fn_ptr(void f(void)) { f(); } } + +EXPORT void call_fn_ptr_with_arg(int32_t f(int32_t)) { + if (f != NULL) { + f(42); + } +} From a36fc5ca41e5595fbb9c9fd4b6755bc8e336f459 Mon Sep 17 00:00:00 2001 From: MousseARaser06 Date: Sun, 1 Feb 2026 13:42:00 +0100 Subject: [PATCH 24/59] FCNTL F_SETFL Ignore creation flags --- src/tools/miri/src/shims/unix/fd.rs | 27 ++++++++++++++++++- .../miri/src/shims/unix/unnamed_socket.rs | 6 ----- .../miri/tests/pass-dep/libc/libc-pipe.rs | 18 +++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 3c2e14c18168..aea6642f47c4 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -194,7 +194,32 @@ fn fcntl( }; let [flag] = check_min_vararg_count("fcntl(fd, F_SETFL, ...)", varargs)?; - let flag = this.read_scalar(flag)?.to_i32()?; + let mut flag = this.read_scalar(flag)?.to_i32()?; + + let allowed_flags = match this.tcx.sess.target.os { + Os::MacOs => + this.eval_libc_i32("O_NONBLOCK") + | this.eval_libc_i32("O_APPEND") + | this.eval_libc_i32("O_ASYNC"), + Os::FreeBsd => + this.eval_libc_i32("O_NONBLOCK") + | this.eval_libc_i32("O_APPEND") + | this.eval_libc_i32("O_DIRECT") + | this.eval_libc_i32("O_ASYNC"), + Os::Solaris | Os::Illumos => + this.eval_libc_i32("O_NONBLOCK") + | this.eval_libc_i32("O_APPEND") + | this.eval_libc_i32("O_DIRECT"), + // Linux + Android match case + _ => + this.eval_libc_i32("O_NONBLOCK") + | this.eval_libc_i32("O_APPEND") + | this.eval_libc_i32("O_DIRECT") + | this.eval_libc_i32("O_NOATIME") + | this.eval_libc_i32("O_ASYNC"), + }; + + flag &= allowed_flags; fd.set_flags(flag, this) } diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index cc371b43a681..b33c294b3a16 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -173,9 +173,6 @@ fn set_flags<'tcx>( // FIXME: File creation flags should be ignored. let o_nonblock = ecx.eval_libc_i32("O_NONBLOCK"); - let o_rdonly = ecx.eval_libc_i32("O_RDONLY"); - let o_wronly = ecx.eval_libc_i32("O_WRONLY"); - let o_rdwr = ecx.eval_libc_i32("O_RDWR"); // O_NONBLOCK flag can be set / unset by user. if flag & o_nonblock == o_nonblock { @@ -185,9 +182,6 @@ fn set_flags<'tcx>( self.is_nonblock.set(false); } - // Ignore all file access mode flags. - flag &= !(o_rdonly | o_wronly | o_rdwr); - // Throw error if there is any unsupported flag. if flag != 0 { throw_unsup_format!( diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index db68daed5396..8f8d4f85c010 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -148,6 +148,24 @@ fn test_pipe_setfl_getfl() { errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDONLY ); + + // Test if ignored flags are indeed ignored. + errno_check(unsafe { + libc::fcntl( + fds[0], + libc::F_SETFL, + libc::O_RDWR + | libc::O_CREAT + | libc::O_EXCL + | libc::O_NOCTTY + | libc::O_TRUNC + | libc::O_NONBLOCK, + ) + }); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), + libc::O_NONBLOCK | libc::O_RDONLY + ); } /// Test the behaviour of F_SETFL/F_GETFL when a fd is blocking. From 7dc80de53de6bf90f94601e76a88323baf2caf5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2026 14:24:53 +0100 Subject: [PATCH 25/59] use ignorelist instead of allowlist for file flags --- src/tools/miri/src/shims/unix/fd.rs | 39 +++++++------------ .../miri/src/shims/unix/unnamed_socket.rs | 2 - 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index aea6642f47c4..460015d4c3cc 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -194,34 +194,21 @@ fn fcntl( }; let [flag] = check_min_vararg_count("fcntl(fd, F_SETFL, ...)", varargs)?; - let mut flag = this.read_scalar(flag)?.to_i32()?; + let flag = this.read_scalar(flag)?.to_i32()?; - let allowed_flags = match this.tcx.sess.target.os { - Os::MacOs => - this.eval_libc_i32("O_NONBLOCK") - | this.eval_libc_i32("O_APPEND") - | this.eval_libc_i32("O_ASYNC"), - Os::FreeBsd => - this.eval_libc_i32("O_NONBLOCK") - | this.eval_libc_i32("O_APPEND") - | this.eval_libc_i32("O_DIRECT") - | this.eval_libc_i32("O_ASYNC"), - Os::Solaris | Os::Illumos => - this.eval_libc_i32("O_NONBLOCK") - | this.eval_libc_i32("O_APPEND") - | this.eval_libc_i32("O_DIRECT"), - // Linux + Android match case - _ => - this.eval_libc_i32("O_NONBLOCK") - | this.eval_libc_i32("O_APPEND") - | this.eval_libc_i32("O_DIRECT") - | this.eval_libc_i32("O_NOATIME") - | this.eval_libc_i32("O_ASYNC"), - }; + // Ignore flags that never get stored by SETFL. + // "File access mode (O_RDONLY, O_WRONLY, O_RDWR) and file + // creation flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) + // in arg are ignored." + let ignored_flags = this.eval_libc_i32("O_RDONLY") + | this.eval_libc_i32("O_WRONLY") + | this.eval_libc_i32("O_RDWR") + | this.eval_libc_i32("O_CREAT") + | this.eval_libc_i32("O_EXCL") + | this.eval_libc_i32("O_NOCTTY") + | this.eval_libc_i32("O_TRUNC"); - flag &= allowed_flags; - - fd.set_flags(flag, this) + fd.set_flags(flag & !ignored_flags, this) } cmd if this.tcx.sess.target.os == Os::MacOs && cmd == this.eval_libc_i32("F_FULLFSYNC") => diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index b33c294b3a16..ea34f72feee5 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -170,8 +170,6 @@ fn set_flags<'tcx>( mut flag: i32, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, Scalar> { - // FIXME: File creation flags should be ignored. - let o_nonblock = ecx.eval_libc_i32("O_NONBLOCK"); // O_NONBLOCK flag can be set / unset by user. From 7f3bbe371f402ddaa7c1dab98d519a3a086e9ad3 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 5 Feb 2026 23:16:43 +0800 Subject: [PATCH 26/59] Report unused features --- compiler/rustc_driver_impl/src/lib.rs | 6 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_feature/src/lib.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 16 ++++- compiler/rustc_interface/src/callbacks.rs | 23 +++++- compiler/rustc_lint_defs/src/builtin.rs | 5 -- compiler/rustc_middle/src/dep_graph/graph.rs | 72 ++++++++++++------- compiler/rustc_middle/src/ty/context.rs | 32 ++++++++- .../rustc_query_impl/src/dep_kind_vtables.rs | 2 +- compiler/rustc_session/src/session.rs | 6 ++ 10 files changed, 129 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 38a11b427c1f..f0629f7591f7 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -338,7 +338,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) } } - Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)) + let linker = Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend); + + tcx.report_unused_features(); + + Some(linker) }); // Linking is done outside the `compiler.enter()` so that the diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index db8f459ef045..db6e9298e235 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1330,7 +1330,7 @@ pub struct BuiltinAttribute { safety: AttributeSafety::Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, - gate: Gated{ + gate: Gated { feature: sym::rustc_attrs, message: "use of an internal attribute", check: Features::rustc_attrs, diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 619726f0d5d8..9d046bdef1cf 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -137,5 +137,5 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option = AtomicRef::new(&(default_track_feature as _)); + #[derive(PartialEq)] enum FeatureStatus { Default, @@ -103,7 +110,12 @@ pub fn enabled_features_iter_stable_order( /// Is the given feature enabled (via `#[feature(...)]`)? pub fn enabled(&self, feature: Symbol) -> bool { - self.enabled_features.contains(&feature) + if self.enabled_features.contains(&feature) { + TRACK_FEATURE(feature); + true + } else { + false + } } } @@ -124,7 +136,7 @@ macro_rules! declare_features { impl Features { $( pub fn $feature(&self) -> bool { - self.enabled_features.contains(&sym::$feature) + self.enabled(sym::$feature) } )* diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 4a1da0f50cc2..9ddbc496e6d4 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -12,8 +12,9 @@ use std::fmt; use rustc_errors::DiagInner; -use rustc_middle::dep_graph::TaskDepsRef; +use rustc_middle::dep_graph::{DepNodeIndex, QuerySideEffect, TaskDepsRef}; use rustc_middle::ty::tls; +use rustc_span::Symbol; fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { tls::with_context_opt(|icx| { @@ -51,6 +52,25 @@ fn track_diagnostic(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) }) } +fn track_feature(feature: Symbol) { + tls::with_context_opt(|icx| { + let Some(icx) = icx else { + return; + }; + let tcx = icx.tcx; + + if let Some(dep_node_index) = tcx.sess.used_features.lock().get(&feature).copied() { + tcx.dep_graph.read_index(DepNodeIndex::from_u32(dep_node_index)); + } else { + let dep_node_index = tcx + .dep_graph + .encode_side_effect(tcx, QuerySideEffect::CheckFeature { symbol: feature }); + tcx.sess.used_features.lock().insert(feature, dep_node_index.as_u32()); + tcx.dep_graph.read_index(dep_node_index); + } + }) +} + /// This is a callback from `rustc_hir` as it cannot access the implicit state /// in `rustc_middle` otherwise. fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -70,4 +90,5 @@ pub fn setup_callbacks() { rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_errors::TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _)); + rustc_feature::TRACK_FEATURE.swap(&(track_feature as _)); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8d498b32cd8a..c1df8aac6f31 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1088,11 +1088,6 @@ /// crate-level [`feature` attributes]. /// /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/ - /// - /// Note: This lint is currently not functional, see [issue #44232] for - /// more details. - /// - /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232 pub UNUSED_FEATURES, Warn, "unused features found in crate-level `#[feature]` directives" diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index a71373c62f38..882e85924778 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -17,6 +17,7 @@ use rustc_macros::{Decodable, Encodable}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; +use rustc_span::Symbol; use tracing::{debug, instrument}; #[cfg(debug_assertions)] use {super::debug::EdgeFilter, std::env}; @@ -45,6 +46,11 @@ pub enum QuerySideEffect { /// the query as green, as that query will have the side /// effect dep node as a dependency. Diagnostic(DiagInner), + /// Records the feature used during query execution. + /// This feature will be inserted into `sess.used_features` + /// if we mark the query as green, as that query will have + /// the side effect dep node as a dependency. + CheckFeature { symbol: Symbol }, } #[derive(Clone)] pub struct DepGraph { @@ -514,29 +520,40 @@ pub fn read_index(&self, dep_node_index: DepNodeIndex) { } } - /// This encodes a diagnostic by creating a node with an unique index and associating - /// `diagnostic` with it, for use in the next session. + /// This encodes a side effect by creating a node with an unique index and associating + /// it with the node, for use in the next session. #[inline] pub fn record_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) { if let Some(ref data) = self.data { read_deps(|task_deps| match task_deps { TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return, TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => { - self.read_index(data.encode_diagnostic(tcx, diagnostic)); + let dep_node_index = data + .encode_side_effect(tcx, QuerySideEffect::Diagnostic(diagnostic.clone())); + self.read_index(dep_node_index); } }) } } - /// This forces a diagnostic node green by running its side effect. `prev_index` would - /// refer to a node created used `encode_diagnostic` in the previous session. + /// This forces a side effect node green by running its side effect. `prev_index` would + /// refer to a node created used `encode_side_effect` in the previous session. #[inline] - pub fn force_diagnostic_node<'tcx>( + pub fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { + if let Some(ref data) = self.data { + data.force_side_effect(tcx, prev_index); + } + } + + #[inline] + pub fn encode_side_effect<'tcx>( &self, tcx: TyCtxt<'tcx>, - prev_index: SerializedDepNodeIndex, - ) { + side_effect: QuerySideEffect, + ) -> DepNodeIndex { if let Some(ref data) = self.data { - data.force_diagnostic_node(tcx, prev_index); + data.encode_side_effect(tcx, side_effect) + } else { + self.next_virtual_depnode_index() } } @@ -673,10 +690,14 @@ pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode) { self.debug_loaded_from_disk.lock().insert(dep_node); } - /// This encodes a diagnostic by creating a node with an unique index and associating - /// `diagnostic` with it, for use in the next session. + /// This encodes a side effect by creating a node with an unique index and associating + /// it with the node, for use in the next session. #[inline] - fn encode_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) -> DepNodeIndex { + fn encode_side_effect<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + side_effect: QuerySideEffect, + ) -> DepNodeIndex { // Use `send_new` so we get an unique index, even though the dep node is not. let dep_node_index = self.current.encoder.send_new( DepNode { @@ -684,28 +705,21 @@ fn encode_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) -> key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO), }, Fingerprint::ZERO, - // We want the side effect node to always be red so it will be forced and emit the - // diagnostic. + // We want the side effect node to always be red so it will be forced and run the + // side effect. std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), ); - let side_effect = QuerySideEffect::Diagnostic(diagnostic.clone()); tcx.store_side_effect(dep_node_index, side_effect); dep_node_index } - /// This forces a diagnostic node green by running its side effect. `prev_index` would - /// refer to a node created used `encode_diagnostic` in the previous session. + /// This forces a side effect node green by running its side effect. `prev_index` would + /// refer to a node created used `encode_side_effect` in the previous session. #[inline] - fn force_diagnostic_node<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { + fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { with_deps(TaskDepsRef::Ignore, || { let side_effect = tcx.load_side_effect(prev_index).unwrap(); - match &side_effect { - QuerySideEffect::Diagnostic(diagnostic) => { - tcx.dcx().emit_diagnostic(diagnostic.clone()); - } - } - // Use `send_and_color` as `promote_node_and_deps_to_current` expects all // green dependencies. `send_and_color` will also prevent multiple nodes // being encoded for concurrent calls. @@ -720,6 +734,16 @@ fn force_diagnostic_node<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedD std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), true, ); + + match &side_effect { + QuerySideEffect::Diagnostic(diagnostic) => { + tcx.dcx().emit_diagnostic(diagnostic.clone()); + } + QuerySideEffect::CheckFeature { symbol } => { + tcx.sess.used_features.lock().insert(*symbol, dep_node_index.as_u32()); + } + } + // This will just overwrite the same value for concurrent calls. tcx.store_side_effect(dep_node_index, side_effect); }) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 27f2a534adb5..68819445a06c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -36,7 +36,7 @@ use rustc_hir::intravisit::VisitorExt; use rustc_hir::lang_items::LangItem; use rustc_hir::limit::Limit; -use rustc_hir::{self as hir, HirId, Node, TraitCandidate, find_attr}; +use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr}; use rustc_index::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; @@ -1688,6 +1688,36 @@ pub fn finish(self) { self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error }); } } + + pub fn report_unused_features(self) { + // Collect first to avoid holding the lock while linting. + let used_features = self.sess.used_features.lock(); + let unused_features = self + .features() + .enabled_features_iter_stable_order() + .filter(|(f, _)| { + !used_features.contains_key(f) + // FIXME: `restricted_std` is used to tell a standard library built + // for a platform that it doesn't know how to support. But it + // could only gate a private mod (see `__restricted_std_workaround`) + // with `cfg(not(restricted_std))`, so it cannot be recorded as used + // in downstream crates. It should never be linted, but should we + // hack this in the linter to ignore it? + && f.as_str() != "restricted_std" + }) + .collect::>(); + + for (feature, span) in unused_features { + self.node_span_lint( + rustc_session::lint::builtin::UNUSED_FEATURES, + CRATE_HIR_ID, + span, + |lint| { + lint.primary_message(format!("feature `{}` is declared but not used", feature)); + }, + ); + } + } } macro_rules! nop_lift { diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs index fa82a0413b1a..847bec8c640f 100644 --- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs +++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs @@ -42,7 +42,7 @@ pub(crate) fn SideEffect<'tcx>() -> DepKindVTable<'tcx> { is_eval_always: false, key_fingerprint_style: KeyFingerprintStyle::Unit, force_from_dep_node_fn: Some(|tcx, _, prev_index| { - tcx.dep_graph.force_diagnostic_node(tcx, prev_index); + tcx.dep_graph.force_side_effect(tcx, prev_index); true }), promote_from_disk_fn: None, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index dc18b05c7576..30840a487273 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -166,6 +166,11 @@ pub struct Session { /// Used by `-Zmir-opt-bisect-limit` to assign an index to each /// optimization-pass execution candidate during this compilation. pub mir_opt_bisect_eval_count: AtomicUsize, + + /// Enabled features that are used in the current compilation. + /// + /// The value is the `DepNodeIndex` of the node encodes the used feature. + pub used_features: Lock>, } #[derive(Clone, Copy)] @@ -1096,6 +1101,7 @@ pub fn build_session( replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler` thin_lto_supported: true, // filled by `run_compiler` mir_opt_bisect_eval_count: AtomicUsize::new(0), + used_features: Lock::default(), }; validate_commandline_args_with_session_available(&sess); From 28b6bcb42d216ec5b77c9cb59c7bbd04c2d1d29d Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 5 Feb 2026 23:22:09 +0800 Subject: [PATCH 27/59] Add tests for unused-features --- tests/incremental/lint-unused-features.rs | 41 +++++++++++++++++++ .../unused-language-features.rs | 25 +++++++++++ .../unused-language-features.stderr | 38 +++++++++++++++++ .../unused-library-features.rs | 13 ++++++ .../unused-library-features.stderr | 34 +++++++++++++++ .../unused-features/used-language-features.rs | 22 ++++++++++ .../unused-features/used-library-features.rs | 17 ++++++++ 7 files changed, 190 insertions(+) create mode 100644 tests/incremental/lint-unused-features.rs create mode 100644 tests/ui/lint/unused-features/unused-language-features.rs create mode 100644 tests/ui/lint/unused-features/unused-language-features.stderr create mode 100644 tests/ui/lint/unused-features/unused-library-features.rs create mode 100644 tests/ui/lint/unused-features/unused-library-features.stderr create mode 100644 tests/ui/lint/unused-features/used-language-features.rs create mode 100644 tests/ui/lint/unused-features/used-library-features.rs diff --git a/tests/incremental/lint-unused-features.rs b/tests/incremental/lint-unused-features.rs new file mode 100644 index 000000000000..a7f66504f6a0 --- /dev/null +++ b/tests/incremental/lint-unused-features.rs @@ -0,0 +1,41 @@ +//@ revisions: rpass cfail +//@ ignore-backends: gcc + +#![deny(unused_features)] + +// Used language features +#![feature(box_patterns)] +#![feature(decl_macro)] +#![cfg_attr(all(), feature(rustc_attrs))] + +// Used library features +#![feature(error_iter)] +//[cfail]~^ ERROR feature `error_iter` is declared but not used +#![cfg_attr(all(), feature(allocator_api))] +//[cfail]~^ ERROR feature `allocator_api` is declared but not used + +pub fn use_box_patterns(b: Box) -> i32 { + let box x = b; + x +} + +macro m() {} +pub fn use_decl_macro() { + m!(); +} + +#[rustc_dummy] +pub fn use_rustc_attrs() {} + +#[cfg(rpass)] +pub fn use_error_iter(e: &(dyn std::error::Error + 'static)) { + for _ in e.sources() {} +} + +#[cfg(rpass)] +pub fn use_allocator_api() { + use std::alloc::Global; + let _ = Vec::::new_in(Global); +} + +fn main() {} diff --git a/tests/ui/lint/unused-features/unused-language-features.rs b/tests/ui/lint/unused-features/unused-language-features.rs new file mode 100644 index 000000000000..9334c1df0408 --- /dev/null +++ b/tests/ui/lint/unused-features/unused-language-features.rs @@ -0,0 +1,25 @@ +#![crate_type = "lib"] +#![deny(unused_features)] + +// Unused language features +#![feature(coroutines)] +//~^ ERROR feature `coroutines` is declared but not used +#![feature(coroutine_clone)] +//~^ ERROR feature `coroutine_clone` is declared but not used +#![feature(stmt_expr_attributes)] +//~^ ERROR feature `stmt_expr_attributes` is declared but not used +#![feature(asm_unwind)] +//~^ ERROR feature `asm_unwind` is declared but not used + +// Enabled via cfg_attr, unused +#![cfg_attr(all(), feature(negative_impls))] +//~^ ERROR feature `negative_impls` is declared but not used + +// Not enabled via cfg_attr, so should not warn even if unused +#![cfg_attr(any(), feature(never_type))] + +macro_rules! use_asm_unwind { + () => { + unsafe { std::arch::asm!("", options(may_unwind)) }; + } +} diff --git a/tests/ui/lint/unused-features/unused-language-features.stderr b/tests/ui/lint/unused-features/unused-language-features.stderr new file mode 100644 index 000000000000..3cede1a6fe72 --- /dev/null +++ b/tests/ui/lint/unused-features/unused-language-features.stderr @@ -0,0 +1,38 @@ +error: feature `coroutines` is declared but not used + --> $DIR/unused-language-features.rs:5:12 + | +LL | #![feature(coroutines)] + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-language-features.rs:2:9 + | +LL | #![deny(unused_features)] + | ^^^^^^^^^^^^^^^ + +error: feature `coroutine_clone` is declared but not used + --> $DIR/unused-language-features.rs:7:12 + | +LL | #![feature(coroutine_clone)] + | ^^^^^^^^^^^^^^^ + +error: feature `stmt_expr_attributes` is declared but not used + --> $DIR/unused-language-features.rs:9:12 + | +LL | #![feature(stmt_expr_attributes)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: feature `asm_unwind` is declared but not used + --> $DIR/unused-language-features.rs:11:12 + | +LL | #![feature(asm_unwind)] + | ^^^^^^^^^^ + +error: feature `negative_impls` is declared but not used + --> $DIR/unused-language-features.rs:15:28 + | +LL | #![cfg_attr(all(), feature(negative_impls))] + | ^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/lint/unused-features/unused-library-features.rs b/tests/ui/lint/unused-features/unused-library-features.rs new file mode 100644 index 000000000000..75afd32e56cb --- /dev/null +++ b/tests/ui/lint/unused-features/unused-library-features.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] +#![deny(unused_features)] + +// Unused library features +#![feature(step_trait)] +//~^ ERROR feature `step_trait` is declared but not used +#![feature(is_sorted)] +//~^ ERROR feature `is_sorted` is declared but not used +//~^^ WARN the feature `is_sorted` has been stable since 1.82.0 and no longer requires an attribute to enable + +// Enabled via cfg_attr, unused +#![cfg_attr(all(), feature(slice_ptr_get))] +//~^ ERROR feature `slice_ptr_get` is declared but not used diff --git a/tests/ui/lint/unused-features/unused-library-features.stderr b/tests/ui/lint/unused-features/unused-library-features.stderr new file mode 100644 index 000000000000..e259058d6c33 --- /dev/null +++ b/tests/ui/lint/unused-features/unused-library-features.stderr @@ -0,0 +1,34 @@ +warning: the feature `is_sorted` has been stable since 1.82.0 and no longer requires an attribute to enable + --> $DIR/unused-library-features.rs:7:12 + | +LL | #![feature(is_sorted)] + | ^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +error: feature `step_trait` is declared but not used + --> $DIR/unused-library-features.rs:5:12 + | +LL | #![feature(step_trait)] + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-library-features.rs:2:9 + | +LL | #![deny(unused_features)] + | ^^^^^^^^^^^^^^^ + +error: feature `is_sorted` is declared but not used + --> $DIR/unused-library-features.rs:7:12 + | +LL | #![feature(is_sorted)] + | ^^^^^^^^^ + +error: feature `slice_ptr_get` is declared but not used + --> $DIR/unused-library-features.rs:12:28 + | +LL | #![cfg_attr(all(), feature(slice_ptr_get))] + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/tests/ui/lint/unused-features/used-language-features.rs b/tests/ui/lint/unused-features/used-language-features.rs new file mode 100644 index 000000000000..7da4866a00d1 --- /dev/null +++ b/tests/ui/lint/unused-features/used-language-features.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![crate_type = "lib"] +#![deny(unused_features)] + +// Used language features +#![feature(box_patterns)] +#![feature(decl_macro)] +#![cfg_attr(all(), feature(rustc_attrs))] + +pub fn use_box_patterns(b: Box) -> i32 { + let box x = b; + x +} + +macro m() {} +pub fn use_decl_macro() { + m!(); +} + +#[rustc_dummy] +pub fn use_rustc_attrs() {} diff --git a/tests/ui/lint/unused-features/used-library-features.rs b/tests/ui/lint/unused-features/used-library-features.rs new file mode 100644 index 000000000000..1747c7741880 --- /dev/null +++ b/tests/ui/lint/unused-features/used-library-features.rs @@ -0,0 +1,17 @@ +//@ check-pass + +#![crate_type = "lib"] +#![deny(unused_features)] + +// Used library features +#![feature(error_iter)] +#![cfg_attr(all(), feature(allocator_api))] + +pub fn use_error_iter(e: &(dyn std::error::Error + 'static)) { + for _ in e.sources() {} +} + +pub fn use_allocator_api() { + use std::alloc::Global; + let _ = Vec::::new_in(Global); +} From d0a182f48560975399309251bc322025bb9eaf35 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 1 Mar 2026 18:31:21 +0800 Subject: [PATCH 28/59] Remove unused features in compiler --- compiler/rustc_errors/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index eab919f08ab5..ada99296f8d5 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,9 +7,7 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![cfg_attr(bootstrap, feature(assert_matches))] #![feature(associated_type_defaults)] -#![feature(box_patterns)] #![feature(default_field_values)] -#![feature(error_reporter)] #![feature(macro_metavar_expr_concat)] #![feature(negative_impls)] #![feature(never_type)] From 0ecb4371975c5a580a9b64e859542f86ca35bb07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 2 Mar 2026 19:31:12 +0100 Subject: [PATCH 29/59] Relax target of `#[rustc_{dump_predicates,object_lifetime_default,variance}]` * `#[dump_predicates]` works on any definition for which query `predicates_of` returns a useful (!) result * `#[rustc_object_lifetime_default]` works on any definition for which query `object_lifetime_default` returns a useful (!) result for type parameters * `#[rustc_variance]` works on any definition for which query `variances_of` returns a useful (!) result When these attributes were ported to the new attribute parsing API, their targets were unnecessarily restricted. --- .../src/attributes/rustc_dump.rs | 23 +++++++++++++++---- .../src/attributes/rustc_internal.rs | 20 +++++++++++++++- .../src/attributes/test_attrs.rs | 3 ++- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 71a8fb0dd47d..3995d757b55b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -1,4 +1,4 @@ -use rustc_hir::Target; +use rustc_hir::{MethodKind, Target}; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; @@ -40,11 +40,24 @@ impl NoArgsAttributeParser for RustcDumpPredicatesParser { const PATH: &[Symbol] = &[sym::rustc_dump_predicates]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ - Allow(Target::Struct), - Allow(Target::Enum), - Allow(Target::Union), - Allow(Target::Trait), + Allow(Target::AssocConst), Allow(Target::AssocTy), + Allow(Target::Const), + Allow(Target::Delegation { mac: false }), + Allow(Target::Delegation { mac: true }), + Allow(Target::Enum), + Allow(Target::Fn), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Struct), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::TyAlias), + Allow(Target::Union), ]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates; } diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 85e7112adbc2..5908b4f77f4d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -593,7 +593,25 @@ impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationPa impl NoArgsAttributeParser for RustcObjectLifetimeDefaultParser { const PATH: &[Symbol] = &[sym::rustc_object_lifetime_default]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::AssocConst), + Allow(Target::AssocTy), + Allow(Target::Const), + Allow(Target::Enum), + Allow(Target::Fn), + Allow(Target::ForeignFn), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Struct), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::TyAlias), + Allow(Target::Union), + ]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcObjectLifetimeDefault; } diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index ac1d360c6280..8df473a09fd4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -99,8 +99,9 @@ impl NoArgsAttributeParser for RustcVarianceParser { const PATH: &[Symbol] = &[sym::rustc_variance]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ - Allow(Target::Struct), Allow(Target::Enum), + Allow(Target::Fn), + Allow(Target::Struct), Allow(Target::Union), ]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance; From 853967a62b2fca1372ae23f95a6f3a420d533660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 2 Mar 2026 16:00:32 +0100 Subject: [PATCH 30/59] Don't crash if `#[rustc_{dump_item_bounds,variance}]` was applied to the wrong item kind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attr parsing already reports an error for this, an subsequent ICE isn't really helpful. Side note: We certainly don't want convert the `bug!(…)`s in the respective queries to delayed bugs! It's imperative that these queries eagerly complain about misuse to prevent dormant bugs! --- .../src/attributes/rustc_dump.rs | 2 +- .../rustc_hir_analysis/src/collect/dump.rs | 33 ++++++++++++++----- .../rustc_hir_analysis/src/variance/dump.rs | 16 ++++++++- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 3995d757b55b..3e1bd28bccc0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -1,5 +1,5 @@ -use rustc_hir::{MethodKind, Target}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::prelude::Allow; diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 8534cc26fd94..3e9c83b12df0 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,4 +1,5 @@ use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::{find_attr, intravisit}; use rustc_middle::hir::nested_filter; @@ -27,7 +28,10 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { for id in tcx.hir_crate_items(()).owners() { - if find_attr!(tcx, id, RustcDumpPredicates) { + #[expect(deprecated)] // we don't want to unnecessarily retrieve the attrs twice in a row. + let attrs = tcx.get_all_attrs(id); + + if find_attr!(attrs, RustcDumpPredicates) { let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates; let span = tcx.def_span(id); @@ -37,15 +41,26 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) { } diag.emit(); } - if find_attr!(tcx, id, RustcDumpItemBounds) { - let bounds = tcx.item_bounds(id).instantiate_identity(); - let span = tcx.def_span(id); - let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str()); - for bound in bounds { - diag.note(format!("{bound:?}")); - } - diag.emit(); + if find_attr!(attrs, RustcDumpItemBounds) { + let name = sym::rustc_dump_item_bounds.as_str(); + + match tcx.def_kind(id) { + DefKind::AssocTy => { + let bounds = tcx.item_bounds(id).instantiate_identity(); + let span = tcx.def_span(id); + + let mut diag = tcx.dcx().struct_span_err(span, name); + for bound in bounds { + diag.note(format!("{bound:?}")); + } + diag.emit() + } + kind => tcx.dcx().span_delayed_bug( + tcx.def_span(id), + format!("attr parsing didn't report an error for `#[{name}]` on {kind:?}"), + ), + }; } } } diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index db17aaf8de1f..30e69418b1c7 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -1,5 +1,6 @@ use std::fmt::Write; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::find_attr; use rustc_middle::ty::{GenericArgs, TyCtxt}; @@ -39,8 +40,21 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) { continue; } + match tcx.def_kind(id) { + DefKind::Fn | DefKind::Enum | DefKind::Struct | DefKind::Union => {} + DefKind::TyAlias if tcx.type_alias_is_lazy(id) => {} + kind => { + let message = format!( + "attr parsing didn't report an error for `#[{}]` on {kind:?}", + rustc_span::sym::rustc_variance, + ); + tcx.dcx().span_delayed_bug(tcx.def_span(id), message); + continue; + } + } + tcx.dcx().emit_err(crate::errors::VariancesOf { - span: tcx.def_span(id.owner_id), + span: tcx.def_span(id), variances: format_variances(tcx, id.owner_id.def_id), }); } From ec324dcc9cede332b3cd87426581e23b4d8bc5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 2 Mar 2026 16:28:43 +0100 Subject: [PATCH 31/59] Don't ignore `#[rustc_variance]` on associated functions --- compiler/rustc_attr_parsing/src/attributes/test_attrs.rs | 4 ++++ compiler/rustc_hir_analysis/src/variance/dump.rs | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 8df473a09fd4..b8f1769e53c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -101,6 +101,10 @@ impl NoArgsAttributeParser for RustcVarianceParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Enum), Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true})), + Allow(Target::Method(MethodKind::TraitImpl)), Allow(Target::Struct), Allow(Target::Union), ]); diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index 30e69418b1c7..84d25bbbe9b9 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -35,13 +35,13 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) { } } - for id in crate_items.free_items() { - if !find_attr!(tcx, id.owner_id, RustcVariance) { + for id in crate_items.owners() { + if !find_attr!(tcx, id, RustcVariance) { continue; } match tcx.def_kind(id) { - DefKind::Fn | DefKind::Enum | DefKind::Struct | DefKind::Union => {} + DefKind::AssocFn | DefKind::Fn | DefKind::Enum | DefKind::Struct | DefKind::Union => {} DefKind::TyAlias if tcx.type_alias_is_lazy(id) => {} kind => { let message = format!( @@ -55,7 +55,7 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) { tcx.dcx().emit_err(crate::errors::VariancesOf { span: tcx.def_span(id), - variances: format_variances(tcx, id.owner_id.def_id), + variances: format_variances(tcx, id.def_id), }); } } From c3a40e26e4e59b85c76bb3ae621c5629076ecc14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 2 Mar 2026 17:26:47 +0100 Subject: [PATCH 32/59] Rename `#[rustc_outlives]` to `#[rustc_dump_inferred_outlives]` --- .../src/attributes/rustc_dump.rs | 14 ++++++++++++++ .../src/attributes/test_attrs.rs | 16 +--------------- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir/src/attrs/data_structures.rs | 6 +++--- .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 +- compiler/rustc_hir_analysis/src/outlives/dump.rs | 4 ++-- compiler/rustc_middle/src/queries.rs | 4 ++-- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- .../rustc-dev-guide/src/compiler-debugging.md | 2 +- .../rfcs/rfc-2093-infer-outlives/cross-crate.rs | 4 ++-- .../rfc-2093-infer-outlives/cross-crate.stderr | 2 +- tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs | 12 ++++++------ .../ui/rfcs/rfc-2093-infer-outlives/enum.stderr | 6 +++--- .../rfcs/rfc-2093-infer-outlives/explicit-dyn.rs | 4 ++-- .../rfc-2093-infer-outlives/explicit-dyn.stderr | 2 +- .../rfc-2093-infer-outlives/explicit-enum.rs | 4 ++-- .../rfc-2093-infer-outlives/explicit-enum.stderr | 2 +- .../explicit-projection.rs | 4 ++-- .../explicit-projection.stderr | 2 +- .../rfc-2093-infer-outlives/explicit-struct.rs | 4 ++-- .../explicit-struct.stderr | 2 +- .../rfc-2093-infer-outlives/explicit-union.rs | 4 ++-- .../explicit-union.stderr | 2 +- .../rfcs/rfc-2093-infer-outlives/nested-enum.rs | 4 ++-- .../rfc-2093-infer-outlives/nested-enum.stderr | 2 +- .../rfc-2093-infer-outlives/nested-regions.rs | 4 ++-- .../nested-regions.stderr | 2 +- .../rfc-2093-infer-outlives/nested-structs.rs | 4 ++-- .../nested-structs.stderr | 2 +- .../rfcs/rfc-2093-infer-outlives/nested-union.rs | 4 ++-- .../rfc-2093-infer-outlives/nested-union.stderr | 2 +- .../rfcs/rfc-2093-infer-outlives/projection.rs | 4 ++-- .../rfc-2093-infer-outlives/projection.stderr | 2 +- .../ui/rfcs/rfc-2093-infer-outlives/reference.rs | 4 ++-- .../rfc-2093-infer-outlives/reference.stderr | 2 +- .../ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs | 4 ++-- .../rfcs/rfc-2093-infer-outlives/self-dyn.stderr | 2 +- .../rfcs/rfc-2093-infer-outlives/self-structs.rs | 4 ++-- .../rfc-2093-infer-outlives/self-structs.stderr | 2 +- 41 files changed, 79 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 3e1bd28bccc0..0160a4b10ec0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -25,6 +25,20 @@ impl NoArgsAttributeParser for RustcDumpDefParentsParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents; } +pub(crate) struct RustcDumpInferredOutlivesParser; + +impl NoArgsAttributeParser for RustcDumpInferredOutlivesParser { + const PATH: &[Symbol] = &[sym::rustc_dump_inferred_outlives]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::TyAlias), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpInferredOutlives; +} + pub(crate) struct RustcDumpItemBoundsParser; impl NoArgsAttributeParser for RustcDumpItemBoundsParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index b8f1769e53c7..ed1bb50da498 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -103,7 +103,7 @@ impl NoArgsAttributeParser for RustcVarianceParser { Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: false })), - Allow(Target::Method(MethodKind::Trait { body: true})), + Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), Allow(Target::Struct), Allow(Target::Union), @@ -220,20 +220,6 @@ impl NoArgsAttributeParser for RustcEvaluateWhereClausesParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEvaluateWhereClauses; } -pub(crate) struct RustcOutlivesParser; - -impl NoArgsAttributeParser for RustcOutlivesParser { - const PATH: &[Symbol] = &[sym::rustc_outlives]; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ - Allow(Target::Struct), - Allow(Target::Enum), - Allow(Target::Union), - Allow(Target::TyAlias), - ]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOutlives; -} - pub(crate) struct TestRunnerParser; impl SingleAttributeParser for TestRunnerParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 802ee56f504b..0f057f77d610 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -281,6 +281,7 @@ mod late { Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -308,7 +309,6 @@ mod late { Single>, Single>, Single>, - Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index db8f459ef045..526c7e912dca 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1419,7 +1419,7 @@ pub struct BuiltinAttribute { rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), rustc_attr!( - TEST, rustc_outlives, Normal, template!(Word), + TEST, rustc_dump_inferred_outlives, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 91409108a753..23e76207810f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1366,6 +1366,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_def_parents]` RustcDumpDefParents, + /// Represents `#[rustc_dump_inferred_outlives]` + RustcDumpInferredOutlives, + /// Represents `#[rustc_dump_item_bounds]` RustcDumpItemBounds, @@ -1499,9 +1502,6 @@ pub enum AttributeKind { /// Represents `#[rustc_offload_kernel]` RustcOffloadKernel, - /// Represents `#[rustc_outlives]` - RustcOutlives, - /// Represents `#[rustc_paren_sugar]`. RustcParenSugar(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index cd41a2b9b28c..e61d102ef1f3 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -124,6 +124,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcDocPrimitive(..) => Yes, RustcDummy => No, RustcDumpDefParents => No, + RustcDumpInferredOutlives => No, RustcDumpItemBounds => No, RustcDumpPredicates => No, RustcDumpUserArgs => No, @@ -163,7 +164,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcObjcSelector { .. } => No, RustcObjectLifetimeDefault => No, RustcOffloadKernel => Yes, - RustcOutlives => No, RustcParenSugar(..) => No, RustcPassByValue(..) => Yes, RustcPassIndirectlyInNonRusticAbis(..) => No, diff --git a/compiler/rustc_hir_analysis/src/outlives/dump.rs b/compiler/rustc_hir_analysis/src/outlives/dump.rs index 671846a35b26..fe8b2a30ab9e 100644 --- a/compiler/rustc_hir_analysis/src/outlives/dump.rs +++ b/compiler/rustc_hir_analysis/src/outlives/dump.rs @@ -5,7 +5,7 @@ pub(crate) fn inferred_outlives(tcx: TyCtxt<'_>) { for id in tcx.hir_free_items() { - if !find_attr!(tcx, id.owner_id, RustcOutlives) { + if !find_attr!(tcx, id.owner_id, RustcDumpInferredOutlives) { continue; } @@ -21,7 +21,7 @@ pub(crate) fn inferred_outlives(tcx: TyCtxt<'_>) { preds.sort(); let span = tcx.def_span(id.owner_id); - let mut err = tcx.dcx().struct_span_err(span, sym::rustc_outlives.as_str()); + let mut err = tcx.dcx().struct_span_err(span, sym::rustc_dump_inferred_outlives.as_str()); for pred in preds { err.note(pred); } diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 0ff38a0f3604..5025510da1bd 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -838,8 +838,8 @@ /// /// E.g., for `struct Foo<'a, T> { x: &'a T }`, this would return `[T: 'a]`. /// - /// **Tip**: You can use `#[rustc_outlives]` on an item to basically print the - /// result of this query for use in UI tests or for debugging purposes. + /// **Tip**: You can use `#[rustc_dump_inferred_outlives]` on an item to basically + /// print the result of this query for use in UI tests or for debugging purposes. query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Clause<'tcx>, Span)] { desc { "computing inferred outlives-predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dacb02afe161..46373adf4461 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -319,6 +319,7 @@ fn check_attributes( | AttributeKind::RustcDocPrimitive(..) | AttributeKind::RustcDummy | AttributeKind::RustcDumpDefParents + | AttributeKind::RustcDumpInferredOutlives | AttributeKind::RustcDumpItemBounds | AttributeKind::RustcDumpPredicates | AttributeKind::RustcDumpUserArgs @@ -355,7 +356,6 @@ fn check_attributes( | AttributeKind::RustcObjcClass { .. } | AttributeKind::RustcObjcSelector { .. } | AttributeKind::RustcOffloadKernel - | AttributeKind::RustcOutlives | AttributeKind::RustcParenSugar(..) | AttributeKind::RustcPassByValue (..) | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9a2d68fc6639..df5ffe9ba740 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1721,6 +1721,7 @@ rustc_driver, rustc_dummy, rustc_dump_def_parents, + rustc_dump_inferred_outlives, rustc_dump_item_bounds, rustc_dump_predicates, rustc_dump_user_args, @@ -1763,7 +1764,6 @@ rustc_object_lifetime_default, rustc_offload_kernel, rustc_on_unimplemented, - rustc_outlives, rustc_paren_sugar, rustc_partition_codegened, rustc_partition_reused, diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index d4c599a6edf7..8bddb985556a 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -275,13 +275,13 @@ Here are some notable ones: |----------------|-------------| | `rustc_def_path` | Dumps the [`def_path_str`] of an item. | | `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. | +| `rustc_dump_inferred_outlives` | Dumps implied bounds of an item. More precisely, the [`inferred_outlives_of`] an item. | | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. | | `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. | | `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. | | `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. | | `rustc_layout` | [See this section](#debugging-type-layouts). | | `rustc_object_lifetime_default` | Dumps the [object lifetime defaults] of an item. | -| `rustc_outlives` | Dumps implied bounds of an item. More precisely, the [`inferred_outlives_of`] an item. | | `rustc_regions` | Dumps NLL closure region requirements. | | `rustc_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. | | `rustc_variances` | Dumps the [variances] of an item. | diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.rs index a9bfeabf16e5..c0625f734b6e 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -struct Foo<'a, T> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, T> { //~ ERROR rustc_dump_inferred_outlives bar: std::slice::IterMut<'a, T> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.stderr index e2a92cf72d56..376bc647158a 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/cross-crate.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/cross-crate.rs:4:1 | LL | struct Foo<'a, T> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs index 71d2d3222655..cfd0d52900ce 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.rs @@ -3,20 +3,20 @@ // Needs an explicit where clause stating outlives condition. (RFC 2093) // Type T needs to outlive lifetime 'a. -#[rustc_outlives] -enum Foo<'a, T> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +enum Foo<'a, T> { //~ ERROR rustc_dump_inferred_outlives One(Bar<'a, T>) } // Type U needs to outlive lifetime 'b -#[rustc_outlives] -struct Bar<'b, U> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Bar<'b, U> { //~ ERROR rustc_dump_inferred_outlives field2: &'b U } // Type K needs to outlive lifetime 'c. -#[rustc_outlives] -enum Ying<'c, K> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +enum Ying<'c, K> { //~ ERROR rustc_dump_inferred_outlives One(&'c Yang) } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/enum.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.stderr index b6ce2450e22a..e17e8705a538 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/enum.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/enum.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/enum.rs:7:1 | LL | enum Foo<'a, T> { @@ -6,7 +6,7 @@ LL | enum Foo<'a, T> { | = note: T: 'a -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/enum.rs:13:1 | LL | struct Bar<'b, U> { @@ -14,7 +14,7 @@ LL | struct Bar<'b, U> { | = note: U: 'b -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/enum.rs:19:1 | LL | enum Ying<'c, K> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.rs index 419fb0a0e458..72a1d1042444 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.rs @@ -3,8 +3,8 @@ trait Trait<'x, T> where T: 'x { } -#[rustc_outlives] -struct Foo<'a, A> //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, A> //~ ERROR rustc_dump_inferred_outlives { foo: Box> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.stderr index 30d1b3e77b1c..3631daf6af76 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-dyn.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/explicit-dyn.rs:7:1 | LL | struct Foo<'a, A> diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.rs index c330c27fea0a..3c1cafba1207 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -enum Foo<'a, U> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +enum Foo<'a, U> { //~ ERROR rustc_dump_inferred_outlives One(Bar<'a, U>) } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.stderr index afc044d88482..58005cca476b 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-enum.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/explicit-enum.rs:4:1 | LL | enum Foo<'a, U> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.rs index 00b89528865a..b7f5e4a1aab6 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.rs @@ -4,8 +4,8 @@ trait Trait<'x, T> where T: 'x { type Type; } -#[rustc_outlives] -struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, A, B> where A: Trait<'a, B> //~ ERROR rustc_dump_inferred_outlives { foo: >::Type } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.stderr index 1c39c984a2a6..4d0844759c95 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-projection.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/explicit-projection.rs:8:1 | LL | struct Foo<'a, A, B> where A: Trait<'a, B> diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.rs index 3d5e610b934b..e067f7469499 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -struct Foo<'b, U> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'b, U> { //~ ERROR rustc_dump_inferred_outlives bar: Bar<'b, U> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.stderr index 4ec3087acffe..76824254c81d 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-struct.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/explicit-struct.rs:4:1 | LL | struct Foo<'b, U> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.rs index 871208b5ba78..dbce3b8400a4 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -union Foo<'b, U: Copy> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +union Foo<'b, U: Copy> { //~ ERROR rustc_dump_inferred_outlives bar: Bar<'b, U> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.stderr index bbb48ef1f261..1f47fb4bf977 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/explicit-union.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/explicit-union.rs:4:1 | LL | union Foo<'b, U: Copy> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.rs index 0cd706e7ab6d..2eb6e7e45e1e 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -enum Foo<'a, T> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +enum Foo<'a, T> { //~ ERROR rustc_dump_inferred_outlives One(Bar<'a, T>) } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.stderr index b584d17ae853..9fe22b7ca85b 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-enum.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/nested-enum.rs:4:1 | LL | enum Foo<'a, T> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.rs index a01c5068171d..b76443842919 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -struct Foo<'a, 'b, T> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, 'b, T> { //~ ERROR rustc_dump_inferred_outlives x: &'a &'b T } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.stderr index 59df869c47a6..f80173bbf074 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-regions.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/nested-regions.rs:4:1 | LL | struct Foo<'a, 'b, T> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.rs index ac6817d22bdc..f33b02b6fa3b 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -struct Foo<'a, T> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, T> { //~ ERROR rustc_dump_inferred_outlives field1: Bar<'a, T> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.stderr index 7e5af7fe6ed5..06439e0e8a99 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-structs.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/nested-structs.rs:4:1 | LL | struct Foo<'a, T> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.rs index 27ebd0b54db5..73332bf0ad65 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -union Foo<'a, T: Copy> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +union Foo<'a, T: Copy> { //~ ERROR rustc_dump_inferred_outlives field1: Bar<'a, T> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.stderr index bb0eea027d5a..b526934ab6d3 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/nested-union.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/nested-union.rs:4:1 | LL | union Foo<'a, T: Copy> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/projection.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.rs index 411c86da1dec..399bddd714db 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/projection.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -struct Foo<'a, T: Iterator> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, T: Iterator> { //~ ERROR rustc_dump_inferred_outlives bar: &'a T::Item } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/projection.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.stderr index 47f3458e0867..e93c2f88bf3e 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/projection.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/projection.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/projection.rs:4:1 | LL | struct Foo<'a, T: Iterator> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/reference.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.rs index a48a3315aa95..84a5ae7133b4 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/reference.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -struct Foo<'a, T> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, T> { //~ ERROR rustc_dump_inferred_outlives bar: &'a T, } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/reference.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.stderr index 329d5ff06abc..7f8156ef6a3d 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/reference.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/reference.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/reference.rs:4:1 | LL | struct Foo<'a, T> { diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs index c53d6c18ff65..c346eaaf2eaf 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.rs @@ -4,8 +4,8 @@ trait Trait<'x, 's, T> where T: 'x, 's: { } -#[rustc_outlives] -struct Foo<'a, 'b, A> //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, 'b, A> //~ ERROR rustc_dump_inferred_outlives { foo: Box> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.stderr index 8f8ee9205471..707711434e0b 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-dyn.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/self-dyn.rs:8:1 | LL | struct Foo<'a, 'b, A> diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.rs b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.rs index 8f2d29d6f17c..1dfccda5c91f 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.rs +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] -#[rustc_outlives] -struct Foo<'a, 'b, T> { //~ ERROR rustc_outlives +#[rustc_dump_inferred_outlives] +struct Foo<'a, 'b, T> { //~ ERROR rustc_dump_inferred_outlives field1: dyn Bar<'a, 'b, T> } diff --git a/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.stderr b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.stderr index 7fef81c26197..eed55b7377c4 100644 --- a/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.stderr +++ b/tests/ui/rfcs/rfc-2093-infer-outlives/self-structs.stderr @@ -1,4 +1,4 @@ -error: rustc_outlives +error: rustc_dump_inferred_outlives --> $DIR/self-structs.rs:4:1 | LL | struct Foo<'a, 'b, T> { From 6bb6b11d9d54ad95a61d8157bf6090ef8a67f8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 2 Mar 2026 18:06:31 +0100 Subject: [PATCH 33/59] Rename `#[rustc_variance]` to `#[rustc_dump_variances]` --- .../src/attributes/rustc_dump.rs | 18 ++++++++ .../src/attributes/test_attrs.rs | 18 -------- compiler/rustc_attr_parsing/src/context.rs | 2 +- .../src/error_codes/E0208.md | 45 ------------------- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 6 +-- .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 +- compiler/rustc_hir_analysis/src/errors.rs | 8 ---- .../rustc_hir_analysis/src/variance/dump.rs | 14 ++---- compiler/rustc_middle/src/queries.rs | 4 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- .../rustc-dev-guide/src/compiler-debugging.md | 2 +- tests/ui/error-codes/E0208.rs | 8 ---- tests/ui/error-codes/E0208.stderr | 8 ---- .../feature-gate-rustc-attrs-1.rs | 6 +-- .../feature-gate-rustc-attrs-1.stderr | 8 ++-- .../ui/variance/variance-associated-consts.rs | 2 +- .../ui/variance/variance-associated-types.rs | 4 +- tests/ui/variance/variance-object-types.rs | 2 +- tests/ui/variance/variance-regions-direct.rs | 14 +++--- .../ui/variance/variance-regions-indirect.rs | 10 ++--- tests/ui/variance/variance-trait-bounds.rs | 8 ++-- .../variance/variance-trait-object-bound.rs | 2 +- tests/ui/variance/variance-types-bounds.rs | 10 ++--- tests/ui/variance/variance-types.rs | 12 ++--- 26 files changed, 72 insertions(+), 147 deletions(-) delete mode 100644 tests/ui/error-codes/E0208.rs delete mode 100644 tests/ui/error-codes/E0208.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 0160a4b10ec0..dea66f3a74b9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -76,6 +76,24 @@ impl NoArgsAttributeParser for RustcDumpPredicatesParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates; } +pub(crate) struct RustcDumpVariancesParser; + +impl NoArgsAttributeParser for RustcDumpVariancesParser { + const PATH: &[Symbol] = &[sym::rustc_dump_variances]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Enum), + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Struct), + Allow(Target::Union), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpVariances; +} + pub(crate) struct RustcDumpVtableParser; impl NoArgsAttributeParser for RustcDumpVtableParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index ed1bb50da498..b01666688f5e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -93,24 +93,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option NoArgsAttributeParser for RustcVarianceParser { - const PATH: &[Symbol] = &[sym::rustc_variance]; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ - Allow(Target::Enum), - Allow(Target::Fn), - Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: false })), - Allow(Target::Method(MethodKind::Trait { body: true })), - Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::Struct), - Allow(Target::Union), - ]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance; -} - pub(crate) struct RustcVarianceOfOpaquesParser; impl NoArgsAttributeParser for RustcVarianceOfOpaquesParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0f057f77d610..915337b09d1d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -285,6 +285,7 @@ mod late { Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -324,7 +325,6 @@ mod late { Single>, Single>, Single>, - Single>, Single>, Single>, // tidy-alphabetical-end diff --git a/compiler/rustc_error_codes/src/error_codes/E0208.md b/compiler/rustc_error_codes/src/error_codes/E0208.md index 2b811b4b8500..f7bbeb293cae 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0208.md +++ b/compiler/rustc_error_codes/src/error_codes/E0208.md @@ -1,47 +1,2 @@ #### This error code is internal to the compiler and will not be emitted with normal Rust code. #### Note: this error code is no longer emitted by the compiler. - -This error code shows the variance of a type's generic parameters. - -Erroneous code example: - -```compile_fail -// NOTE: this feature is perma-unstable and should *only* be used for -// testing purposes. -#![allow(internal_features)] -#![feature(rustc_attrs)] - -#[rustc_variance] -struct Foo<'a, T> { // error: deliberate error to display type's variance - t: &'a mut T, -} -``` - -which produces the following error: - -```text -error: [-, o] - --> :4:1 - | -4 | struct Foo<'a, T> { - | ^^^^^^^^^^^^^^^^^ -``` - -*Note that while `#[rustc_variance]` still exists and is used within the* -*compiler, it no longer is marked as `E0208` and instead has no error code.* - -This error is deliberately triggered with the `#[rustc_variance]` attribute -(`#![feature(rustc_attrs)]` must be enabled) and helps to show you the variance -of the type's generic parameters. You can read more about variance and -subtyping in [this section of the Rustonomicon]. For a more in depth look at -variance (including a more complete list of common variances) see -[this section of the Reference]. For information on how variance is implemented -in the compiler, see [this section of `rustc-dev-guide`]. - -This error can be easily fixed by removing the `#[rustc_variance]` attribute, -the compiler's suggestion to comment it out can be applied automatically with -`rustfix`. - -[this section of the Rustonomicon]: https://doc.rust-lang.org/nomicon/subtyping.html -[this section of the Reference]: https://doc.rust-lang.org/reference/subtyping.html#variance -[this section of `rustc-dev-guide`]: https://rustc-dev-guide.rust-lang.org/variance.html diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 526c7e912dca..faf29dd467e1 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1439,7 +1439,7 @@ pub struct BuiltinAttribute { WarnFollowing, EncodeCrossCrate::Yes ), rustc_attr!( - TEST, rustc_variance, Normal, template!(Word), + TEST, rustc_dump_variances, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 23e76207810f..d4fc0be8595e 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1378,6 +1378,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_user_args]` RustcDumpUserArgs, + /// Represents `#[rustc_dump_variances]` + RustcDumpVariances, + /// Represents `#[rustc_dump_vtable]` RustcDumpVtable(Span), @@ -1574,9 +1577,6 @@ pub enum AttributeKind { /// Represents `#[rustc_unsafe_specialization_marker]`. RustcUnsafeSpecializationMarker(Span), - /// Represents `#[rustc_variance]` - RustcVariance, - /// Represents `#[rustc_variance_of_opaques]` RustcVarianceOfOpaques, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e61d102ef1f3..c36282439a1c 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -128,6 +128,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcDumpItemBounds => No, RustcDumpPredicates => No, RustcDumpUserArgs => No, + RustcDumpVariances => No, RustcDumpVtable(..) => No, RustcDynIncompatibleTrait(..) => No, RustcEffectiveVisibility => Yes, @@ -185,7 +186,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcThenThisWouldNeed(..) => No, RustcTrivialFieldReads => Yes, RustcUnsafeSpecializationMarker(..) => No, - RustcVariance => No, RustcVarianceOfOpaques => No, Sanitize { .. } => No, ShouldPanic { .. } => No, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 5cda2ac660fb..1c999f1ffc93 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -735,14 +735,6 @@ pub(crate) enum CannotCaptureLateBound { }, } -#[derive(Diagnostic)] -#[diag("{$variances}")] -pub(crate) struct VariancesOf { - #[primary_span] - pub span: Span, - pub variances: String, -} - #[derive(Diagnostic)] #[diag("{$ty}")] pub(crate) struct TypeOf<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index 84d25bbbe9b9..1c1216061973 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -28,15 +28,12 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) { if find_attr!(tcx, crate, RustcVarianceOfOpaques) { for id in crate_items.opaques() { - tcx.dcx().emit_err(crate::errors::VariancesOf { - span: tcx.def_span(id), - variances: format_variances(tcx, id), - }); + tcx.dcx().span_err(tcx.def_span(id), format_variances(tcx, id)); } } for id in crate_items.owners() { - if !find_attr!(tcx, id, RustcVariance) { + if !find_attr!(tcx, id, RustcDumpVariances) { continue; } @@ -46,16 +43,13 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) { kind => { let message = format!( "attr parsing didn't report an error for `#[{}]` on {kind:?}", - rustc_span::sym::rustc_variance, + rustc_span::sym::rustc_dump_variances, ); tcx.dcx().span_delayed_bug(tcx.def_span(id), message); continue; } } - tcx.dcx().emit_err(crate::errors::VariancesOf { - span: tcx.def_span(id), - variances: format_variances(tcx, id.def_id), - }); + tcx.dcx().span_err(tcx.def_span(id), format_variances(tcx, id.def_id)); } } diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 5025510da1bd..42c4ff5e7afe 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1046,8 +1046,8 @@ /// The list of variances corresponds to the list of (early-bound) generic /// parameters of the item (including its parents). /// - /// **Tip**: You can use `#[rustc_variance]` on an item to basically print the - /// result of this query for use in UI tests or for debugging purposes. + /// **Tip**: You can use `#[rustc_dump_variances]` on an item to basically print + /// the result of this query for use in UI tests or for debugging purposes. query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { desc { "computing the variances of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 46373adf4461..8a729a8f4b6a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -323,6 +323,7 @@ fn check_attributes( | AttributeKind::RustcDumpItemBounds | AttributeKind::RustcDumpPredicates | AttributeKind::RustcDumpUserArgs + | AttributeKind::RustcDumpVariances | AttributeKind::RustcDumpVtable(..) | AttributeKind::RustcDynIncompatibleTrait(..) | AttributeKind::RustcEffectiveVisibility @@ -376,7 +377,6 @@ fn check_attributes( | AttributeKind::RustcThenThisWouldNeed(..) | AttributeKind::RustcTrivialFieldReads | AttributeKind::RustcUnsafeSpecializationMarker(..) - | AttributeKind::RustcVariance | AttributeKind::RustcVarianceOfOpaques | AttributeKind::ShouldPanic { .. } | AttributeKind::TestRunner(..) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index df5ffe9ba740..ccbacea4c13e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1725,6 +1725,7 @@ rustc_dump_item_bounds, rustc_dump_predicates, rustc_dump_user_args, + rustc_dump_variances, rustc_dump_vtable, rustc_dyn_incompatible_trait, rustc_effective_visibility, @@ -1793,7 +1794,6 @@ rustc_then_this_would_need, rustc_trivial_field_reads, rustc_unsafe_specialization_marker, - rustc_variance, rustc_variance_of_opaques, rustdoc, rustdoc_internals, diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index 8bddb985556a..d4eb004a0eef 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -278,13 +278,13 @@ Here are some notable ones: | `rustc_dump_inferred_outlives` | Dumps implied bounds of an item. More precisely, the [`inferred_outlives_of`] an item. | | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. | | `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. | +| `rustc_dump_variances` | Dumps the [variances] of an item. | | `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. | | `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. | | `rustc_layout` | [See this section](#debugging-type-layouts). | | `rustc_object_lifetime_default` | Dumps the [object lifetime defaults] of an item. | | `rustc_regions` | Dumps NLL closure region requirements. | | `rustc_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. | -| `rustc_variances` | Dumps the [variances] of an item. | Right below you can find elaborate explainers on a selected few. diff --git a/tests/ui/error-codes/E0208.rs b/tests/ui/error-codes/E0208.rs deleted file mode 100644 index 2713ba6ed6cb..000000000000 --- a/tests/ui/error-codes/E0208.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_variance] -struct Foo<'a, T> { //~ ERROR ['a: +, T: o] - t: &'a mut T, -} - -fn main() {} diff --git a/tests/ui/error-codes/E0208.stderr b/tests/ui/error-codes/E0208.stderr deleted file mode 100644 index a39e93afab3e..000000000000 --- a/tests/ui/error-codes/E0208.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: ['a: +, T: o] - --> $DIR/E0208.rs:4:1 - | -LL | struct Foo<'a, T> { - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs index beddfd87a5e7..f9b097fdd215 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs @@ -7,10 +7,10 @@ //~| NOTE the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized struct Foo {} -#[rustc_variance] +#[rustc_dump_variances] //~^ ERROR use of an internal attribute [E0658] -//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable -//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests +//~| NOTE the `#[rustc_dump_variances]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_dump_variances]` attribute is used for rustc unit tests enum E {} fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 6588229b7d56..81d8a750b897 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -12,12 +12,12 @@ LL | #[rustc_nonnull_optimization_guaranteed] error[E0658]: use of an internal attribute --> $DIR/feature-gate-rustc-attrs-1.rs:10:1 | -LL | #[rustc_variance] - | ^^^^^^^^^^^^^^^^^ +LL | #[rustc_dump_variances] + | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable - = note: the `#[rustc_variance]` attribute is used for rustc unit tests + = note: the `#[rustc_dump_variances]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_dump_variances]` attribute is used for rustc unit tests error: aborting due to 2 previous errors diff --git a/tests/ui/variance/variance-associated-consts.rs b/tests/ui/variance/variance-associated-consts.rs index 97edb7e266ad..e53533ae30d7 100644 --- a/tests/ui/variance/variance-associated-consts.rs +++ b/tests/ui/variance/variance-associated-consts.rs @@ -9,7 +9,7 @@ trait Trait { const Const: usize; } -#[rustc_variance] +#[rustc_dump_variances] struct Foo { //~ ERROR [T: o] field: [u8; ::Const] //~^ ERROR: unconstrained generic constant diff --git a/tests/ui/variance/variance-associated-types.rs b/tests/ui/variance/variance-associated-types.rs index 07ff41062e88..00e5338880a1 100644 --- a/tests/ui/variance/variance-associated-types.rs +++ b/tests/ui/variance/variance-associated-types.rs @@ -9,12 +9,12 @@ trait Trait<'a> { fn method(&'a self) { } } -#[rustc_variance] +#[rustc_dump_variances] struct Foo<'a, T : Trait<'a>> { //~ ERROR ['a: +, T: +] field: (T, &'a ()) } -#[rustc_variance] +#[rustc_dump_variances] struct Bar<'a, T : Trait<'a>> { //~ ERROR ['a: o, T: o] field: >::Type } diff --git a/tests/ui/variance/variance-object-types.rs b/tests/ui/variance/variance-object-types.rs index fd03dec98249..10e1e3ebd09a 100644 --- a/tests/ui/variance/variance-object-types.rs +++ b/tests/ui/variance/variance-object-types.rs @@ -3,7 +3,7 @@ // For better or worse, associated types are invariant, and hence we // get an invariant result for `'a`. -#[rustc_variance] +#[rustc_dump_variances] struct Foo<'a> { //~ ERROR ['a: o] x: Box &'a i32 + 'static> } diff --git a/tests/ui/variance/variance-regions-direct.rs b/tests/ui/variance/variance-regions-direct.rs index 2bcacec33ea5..1211db355baf 100644 --- a/tests/ui/variance/variance-regions-direct.rs +++ b/tests/ui/variance/variance-regions-direct.rs @@ -5,7 +5,7 @@ // Regions that just appear in normal spots are contravariant: -#[rustc_variance] +#[rustc_dump_variances] struct Test2<'a, 'b, 'c> { //~ ERROR ['a: +, 'b: +, 'c: +] x: &'a isize, y: &'b [isize], @@ -14,7 +14,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR ['a: +, 'b: +, 'c: +] // Those same annotations in function arguments become covariant: -#[rustc_variance] +#[rustc_dump_variances] struct Test3<'a, 'b, 'c> { //~ ERROR ['a: -, 'b: -, 'c: -] x: extern "Rust" fn(&'a isize), y: extern "Rust" fn(&'b [isize]), @@ -23,7 +23,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR ['a: -, 'b: -, 'c: -] // Mutability induces invariance: -#[rustc_variance] +#[rustc_dump_variances] struct Test4<'a, 'b:'a> { //~ ERROR ['a: +, 'b: o] x: &'a mut &'b isize, } @@ -31,7 +31,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR ['a: +, 'b: o] // Mutability induces invariance, even when in a // contravariant context: -#[rustc_variance] +#[rustc_dump_variances] struct Test5<'a, 'b:'a> { //~ ERROR ['a: -, 'b: o] x: extern "Rust" fn(&'a mut &'b isize), } @@ -41,14 +41,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR ['a: -, 'b: o] // an argument list (which is contravariant), that // argument list occurs in an invariant context. -#[rustc_variance] +#[rustc_dump_variances] struct Test6<'a, 'b:'a> { //~ ERROR ['a: +, 'b: o] x: &'a mut extern "Rust" fn(&'b isize), } // No uses at all is bivariant: -#[rustc_variance] +#[rustc_dump_variances] struct Test7<'a> { //~ ERROR ['a: *] //~^ ERROR: `'a` is never used x: isize @@ -56,7 +56,7 @@ struct Test7<'a> { //~ ERROR ['a: *] // Try enums too. -#[rustc_variance] +#[rustc_dump_variances] enum Test8<'a, 'b, 'c:'b> { //~ ERROR ['a: -, 'b: +, 'c: o] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), diff --git a/tests/ui/variance/variance-regions-indirect.rs b/tests/ui/variance/variance-regions-indirect.rs index aaa4d3f87799..0c5348ae0e40 100644 --- a/tests/ui/variance/variance-regions-indirect.rs +++ b/tests/ui/variance/variance-regions-indirect.rs @@ -4,7 +4,7 @@ #![feature(rustc_attrs)] -#[rustc_variance] +#[rustc_dump_variances] enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR ['a: -, 'b: +, 'c: o, 'd: *] //~^ ERROR: `'d` is never used Test8A(extern "Rust" fn(&'a isize)), @@ -12,25 +12,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR ['a: -, 'b: +, 'c: o, 'd: *] Test8C(&'b mut &'c str), } -#[rustc_variance] +#[rustc_dump_variances] struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR ['w: *, 'x: o, 'y: +, 'z: -] //~^ ERROR: `'w` is never used f: Base<'z, 'y, 'x, 'w> } -#[rustc_variance] // Combine - and + to yield o +#[rustc_dump_variances] // Combine - and + to yield o struct Derived2<'a, 'b:'a, 'c> { //~ ERROR ['a: o, 'b: o, 'c: *] //~^ ERROR: `'c` is never used f: Base<'a, 'a, 'b, 'c> } -#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) +#[rustc_dump_variances] // Combine + and o to yield o (just pay attention to 'a here) struct Derived3<'a:'b, 'b, 'c> { //~ ERROR ['a: o, 'b: +, 'c: *] //~^ ERROR: `'c` is never used f: Base<'a, 'b, 'a, 'c> } -#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) +#[rustc_dump_variances] // Combine + and * to yield + (just pay attention to 'a here) struct Derived4<'a, 'b, 'c:'b> { //~ ERROR ['a: -, 'b: +, 'c: o] f: Base<'a, 'b, 'c, 'a> } diff --git a/tests/ui/variance/variance-trait-bounds.rs b/tests/ui/variance/variance-trait-bounds.rs index f86fa2bbef7a..43f19378ee54 100644 --- a/tests/ui/variance/variance-trait-bounds.rs +++ b/tests/ui/variance/variance-trait-bounds.rs @@ -12,24 +12,24 @@ trait Setter { fn get(&self, _: T); } -#[rustc_variance] +#[rustc_dump_variances] struct TestStruct> { //~ ERROR [U: +, T: +] t: T, u: U } -#[rustc_variance] +#[rustc_dump_variances] enum TestEnum> { //~ ERROR [U: *, T: +] //~^ ERROR: `U` is never used Foo(T) } -#[rustc_variance] +#[rustc_dump_variances] struct TestContraStruct> { //~ ERROR [U: *, T: +] //~^ ERROR: `U` is never used t: T } -#[rustc_variance] +#[rustc_dump_variances] struct TestBox+Setter> { //~ ERROR [U: *, T: +] //~^ ERROR: `U` is never used t: T diff --git a/tests/ui/variance/variance-trait-object-bound.rs b/tests/ui/variance/variance-trait-object-bound.rs index ca80c6b6dce2..03dbdfb0bd37 100644 --- a/tests/ui/variance/variance-trait-object-bound.rs +++ b/tests/ui/variance/variance-trait-object-bound.rs @@ -10,7 +10,7 @@ trait T { fn foo(&self); } -#[rustc_variance] +#[rustc_dump_variances] struct TOption<'a> { //~ ERROR ['a: +] v: Option>, } diff --git a/tests/ui/variance/variance-types-bounds.rs b/tests/ui/variance/variance-types-bounds.rs index f4738a2dae1a..b0c382560098 100644 --- a/tests/ui/variance/variance-types-bounds.rs +++ b/tests/ui/variance/variance-types-bounds.rs @@ -3,24 +3,24 @@ #![feature(rustc_attrs)] -#[rustc_variance] +#[rustc_dump_variances] struct TestImm { //~ ERROR [A: +, B: +] x: A, y: B, } -#[rustc_variance] +#[rustc_dump_variances] struct TestMut { //~ ERROR [A: +, B: o] x: A, y: &'static mut B, } -#[rustc_variance] +#[rustc_dump_variances] struct TestIndirect { //~ ERROR [A: +, B: o] m: TestMut } -#[rustc_variance] +#[rustc_dump_variances] struct TestIndirect2 { //~ ERROR [A: o, B: o] n: TestMut, m: TestMut @@ -34,7 +34,7 @@ trait Setter { fn set(&mut self, a: A); } -#[rustc_variance] +#[rustc_dump_variances] struct TestObject { //~ ERROR [A: o, R: o] n: Box+Send>, m: Box+Send>, diff --git a/tests/ui/variance/variance-types.rs b/tests/ui/variance/variance-types.rs index aa336d1b424c..3b3ac929a263 100644 --- a/tests/ui/variance/variance-types.rs +++ b/tests/ui/variance/variance-types.rs @@ -6,32 +6,32 @@ // Check that a type parameter which is only used in a trait bound is // not considered bivariant. -#[rustc_variance] +#[rustc_dump_variances] struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR ['a: +, A: o, B: o] t: &'a mut (A,B) } -#[rustc_variance] +#[rustc_dump_variances] struct InvariantCell { //~ ERROR [A: o] t: Cell } -#[rustc_variance] +#[rustc_dump_variances] struct InvariantIndirect { //~ ERROR [A: o] t: InvariantCell } -#[rustc_variance] +#[rustc_dump_variances] struct Covariant { //~ ERROR [A: +] t: A, u: fn() -> A } -#[rustc_variance] +#[rustc_dump_variances] struct Contravariant { //~ ERROR [A: -] t: fn(A) } -#[rustc_variance] +#[rustc_dump_variances] enum Enum { //~ ERROR [A: +, B: -, C: o] Foo(Covariant), Bar(Contravariant), From 6af78890bc23b160f3741cba0dd5210675c3b95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 2 Mar 2026 18:13:09 +0100 Subject: [PATCH 34/59] Rename `#![rustc_variance_of_opaques]` to `#![rustc_dump_variances_of_opaques]` --- compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs | 9 +++++++++ compiler/rustc_attr_parsing/src/attributes/test_attrs.rs | 9 --------- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir/src/attrs/data_structures.rs | 6 +++--- compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 2 +- compiler/rustc_hir_analysis/src/variance/dump.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 +- tests/ui/impl-trait/capture-lifetime-not-in-hir.rs | 2 +- tests/ui/impl-trait/implicit-capture-late.rs | 2 +- tests/ui/impl-trait/in-trait/variance.rs | 2 +- .../impl-trait/precise-capturing/capturing-implicit.rs | 2 +- tests/ui/impl-trait/variance.rs | 2 +- tests/ui/traits/const-traits/variance.rs | 2 +- tests/ui/type-alias-impl-trait/variance.rs | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index dea66f3a74b9..06bf77771deb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -94,6 +94,15 @@ impl NoArgsAttributeParser for RustcDumpVariancesParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpVariances; } +pub(crate) struct RustcDumpVariancesOfOpaquesParser; + +impl NoArgsAttributeParser for RustcDumpVariancesOfOpaquesParser { + const PATH: &[Symbol] = &[sym::rustc_dump_variances_of_opaques]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpVariancesOfOpaques; +} + pub(crate) struct RustcDumpVtableParser; impl NoArgsAttributeParser for RustcDumpVtableParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index b01666688f5e..2775eab1b5d9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -93,15 +93,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option NoArgsAttributeParser for RustcVarianceOfOpaquesParser { - const PATH: &[Symbol] = &[sym::rustc_variance_of_opaques]; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVarianceOfOpaques; -} - pub(crate) struct ReexportTestHarnessMainParser; impl SingleAttributeParser for ReexportTestHarnessMainParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 915337b09d1d..8e871cd17003 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -285,6 +285,7 @@ mod late { Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -324,7 +325,6 @@ mod late { Single>, Single>, Single>, - Single>, Single>, Single>, // tidy-alphabetical-end diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index faf29dd467e1..f18e7e3146a3 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1443,7 +1443,7 @@ pub struct BuiltinAttribute { WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_variance_of_opaques, Normal, template!(Word), + TEST, rustc_dump_variances_of_opaques, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index d4fc0be8595e..426eec68ca6f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1381,6 +1381,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_variances]` RustcDumpVariances, + /// Represents `#[rustc_dump_variances_of_opaques]` + RustcDumpVariancesOfOpaques, + /// Represents `#[rustc_dump_vtable]` RustcDumpVtable(Span), @@ -1577,9 +1580,6 @@ pub enum AttributeKind { /// Represents `#[rustc_unsafe_specialization_marker]`. RustcUnsafeSpecializationMarker(Span), - /// Represents `#[rustc_variance_of_opaques]` - RustcVarianceOfOpaques, - /// Represents `#[sanitize]` /// /// the on set and off set are distjoint since there's a third option: unset. diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index c36282439a1c..1237e8f0d133 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -129,6 +129,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcDumpPredicates => No, RustcDumpUserArgs => No, RustcDumpVariances => No, + RustcDumpVariancesOfOpaques => No, RustcDumpVtable(..) => No, RustcDynIncompatibleTrait(..) => No, RustcEffectiveVisibility => Yes, @@ -186,7 +187,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcThenThisWouldNeed(..) => No, RustcTrivialFieldReads => Yes, RustcUnsafeSpecializationMarker(..) => No, - RustcVarianceOfOpaques => No, Sanitize { .. } => No, ShouldPanic { .. } => No, Stability { .. } => Yes, diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index 1c1216061973..2e1746473695 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -26,7 +26,7 @@ fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { pub(crate) fn variances(tcx: TyCtxt<'_>) { let crate_items = tcx.hir_crate_items(()); - if find_attr!(tcx, crate, RustcVarianceOfOpaques) { + if find_attr!(tcx, crate, RustcDumpVariancesOfOpaques) { for id in crate_items.opaques() { tcx.dcx().span_err(tcx.def_span(id), format_variances(tcx, id)); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8a729a8f4b6a..4d5c793bdd88 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -324,6 +324,7 @@ fn check_attributes( | AttributeKind::RustcDumpPredicates | AttributeKind::RustcDumpUserArgs | AttributeKind::RustcDumpVariances + | AttributeKind::RustcDumpVariancesOfOpaques | AttributeKind::RustcDumpVtable(..) | AttributeKind::RustcDynIncompatibleTrait(..) | AttributeKind::RustcEffectiveVisibility @@ -377,7 +378,6 @@ fn check_attributes( | AttributeKind::RustcThenThisWouldNeed(..) | AttributeKind::RustcTrivialFieldReads | AttributeKind::RustcUnsafeSpecializationMarker(..) - | AttributeKind::RustcVarianceOfOpaques | AttributeKind::ShouldPanic { .. } | AttributeKind::TestRunner(..) | AttributeKind::ThreadLocal diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ccbacea4c13e..de486138217d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1726,6 +1726,7 @@ rustc_dump_predicates, rustc_dump_user_args, rustc_dump_variances, + rustc_dump_variances_of_opaques, rustc_dump_vtable, rustc_dyn_incompatible_trait, rustc_effective_visibility, @@ -1794,7 +1795,6 @@ rustc_then_this_would_need, rustc_trivial_field_reads, rustc_unsafe_specialization_marker, - rustc_variance_of_opaques, rustdoc, rustdoc_internals, rustdoc_missing_doc_code_examples, diff --git a/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs b/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs index 2fde0f200c0e..a5a6c310b7bf 100644 --- a/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs +++ b/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs @@ -1,5 +1,5 @@ #![feature(rustc_attrs)] -#![rustc_variance_of_opaques] +#![rustc_dump_variances_of_opaques] trait Bar<'a> { type Assoc: From<()>; diff --git a/tests/ui/impl-trait/implicit-capture-late.rs b/tests/ui/impl-trait/implicit-capture-late.rs index 57a00357c711..d7ef8fb88806 100644 --- a/tests/ui/impl-trait/implicit-capture-late.rs +++ b/tests/ui/impl-trait/implicit-capture-late.rs @@ -2,7 +2,7 @@ #![feature(rustc_attrs)] #![allow(internal_features)] -#![rustc_variance_of_opaques] +#![rustc_dump_variances_of_opaques] use std::ops::Deref; diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index f0b8c05b2d71..b1e7d91fc6ad 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -1,6 +1,6 @@ #![feature(rustc_attrs)] #![allow(internal_features)] -#![rustc_variance_of_opaques] +#![rustc_dump_variances_of_opaques] trait Foo<'i> { fn implicit_capture_early<'a: 'a>() -> impl Sized {} diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs index 7b53b20ceffa..255f093b3cca 100644 --- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs +++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs @@ -2,7 +2,7 @@ #![feature(rustc_attrs)] #![feature(type_alias_impl_trait)] -#![rustc_variance_of_opaques] +#![rustc_dump_variances_of_opaques] fn foo(x: &()) -> impl IntoIterator + use<> { //~^ ERROR ['_: o] diff --git a/tests/ui/impl-trait/variance.rs b/tests/ui/impl-trait/variance.rs index e73e0c623aa4..d08e2297932e 100644 --- a/tests/ui/impl-trait/variance.rs +++ b/tests/ui/impl-trait/variance.rs @@ -3,7 +3,7 @@ #![feature(rustc_attrs)] #![allow(internal_features)] -#![rustc_variance_of_opaques] +#![rustc_dump_variances_of_opaques] trait Captures<'a> {} impl Captures<'_> for T {} diff --git a/tests/ui/traits/const-traits/variance.rs b/tests/ui/traits/const-traits/variance.rs index 73014703adc0..711b810e3716 100644 --- a/tests/ui/traits/const-traits/variance.rs +++ b/tests/ui/traits/const-traits/variance.rs @@ -1,6 +1,6 @@ #![feature(rustc_attrs, const_trait_impl)] #![allow(internal_features)] -#![rustc_variance_of_opaques] +#![rustc_dump_variances_of_opaques] const trait Foo {} diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs index d9140695dae2..5b2d23d631b4 100644 --- a/tests/ui/type-alias-impl-trait/variance.rs +++ b/tests/ui/type-alias-impl-trait/variance.rs @@ -1,6 +1,6 @@ #![feature(rustc_attrs, type_alias_impl_trait, impl_trait_in_assoc_type)] #![allow(internal_features)] -#![rustc_variance_of_opaques] +#![rustc_dump_variances_of_opaques] trait Captures<'a> {} impl Captures<'_> for T {} From 722fcbb72e3e312153dcc142108fac6efef40538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 2 Mar 2026 18:33:02 +0100 Subject: [PATCH 35/59] Rename `#[rustc_object_lifetime_default]` to `#[rustc_dump_object_lifetime_defaults]` --- .../src/attributes/rustc_dump.rs | 27 +++++++++++++++++++ .../src/attributes/rustc_internal.rs | 27 ------------------- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 6 ++--- .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 +- compiler/rustc_middle/src/queries.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 10 +++---- compiler/rustc_passes/src/errors.rs | 8 ------ compiler/rustc_span/src/symbol.rs | 2 +- .../rustc-dev-guide/src/compiler-debugging.md | 2 +- .../object-lifetime-default.rs | 14 +++++----- 12 files changed, 48 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 06bf77771deb..7c771a71bf63 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -48,6 +48,33 @@ impl NoArgsAttributeParser for RustcDumpItemBoundsParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds; } +pub(crate) struct RustcDumpObjectLifetimeDefaultsParser; + +impl NoArgsAttributeParser for RustcDumpObjectLifetimeDefaultsParser { + const PATH: &[Symbol] = &[sym::rustc_dump_object_lifetime_defaults]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::AssocConst), + Allow(Target::AssocTy), + Allow(Target::Const), + Allow(Target::Enum), + Allow(Target::Fn), + Allow(Target::ForeignFn), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Struct), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::TyAlias), + Allow(Target::Union), + ]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpObjectLifetimeDefaults; +} + pub(crate) struct RustcDumpPredicatesParser; impl NoArgsAttributeParser for RustcDumpPredicatesParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 5908b4f77f4d..e8b4cb343794 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -588,33 +588,6 @@ impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationPa const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintUntrackedQueryInformation; } -pub(crate) struct RustcObjectLifetimeDefaultParser; - -impl NoArgsAttributeParser for RustcObjectLifetimeDefaultParser { - const PATH: &[Symbol] = &[sym::rustc_object_lifetime_default]; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ - Allow(Target::AssocConst), - Allow(Target::AssocTy), - Allow(Target::Const), - Allow(Target::Enum), - Allow(Target::Fn), - Allow(Target::ForeignFn), - Allow(Target::Impl { of_trait: false }), - Allow(Target::Impl { of_trait: true }), - Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: false })), - Allow(Target::Method(MethodKind::Trait { body: true })), - Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::Struct), - Allow(Target::Trait), - Allow(Target::TraitAlias), - Allow(Target::TyAlias), - Allow(Target::Union), - ]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcObjectLifetimeDefault; -} - pub(crate) struct RustcSimdMonomorphizeLaneLimitParser; impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8e871cd17003..190568bed508 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -283,6 +283,7 @@ mod late { Single>, Single>, Single>, + Single>, Single>, Single>, Single>, @@ -309,7 +310,6 @@ mod late { Single>, Single>, Single>, - Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index f18e7e3146a3..f586cbb1d715 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1531,7 +1531,7 @@ pub struct BuiltinAttribute { WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( - TEST, rustc_object_lifetime_default, Normal, template!(Word), + TEST, rustc_dump_object_lifetime_defaults, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 426eec68ca6f..e8476c3d8c73 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1372,6 +1372,9 @@ pub enum AttributeKind { /// Represents `#[rustc_dump_item_bounds]` RustcDumpItemBounds, + /// Represents `#[rustc_dump_object_lifetime_defaults]`. + RustcDumpObjectLifetimeDefaults, + /// Represents `#[rustc_dump_predicates]` RustcDumpPredicates, @@ -1502,9 +1505,6 @@ pub enum AttributeKind { span: Span, }, - /// Represents `#[rustc_object_lifetime_default]`. - RustcObjectLifetimeDefault, - /// Represents `#[rustc_offload_kernel]` RustcOffloadKernel, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 1237e8f0d133..27128f699637 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -126,6 +126,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcDumpDefParents => No, RustcDumpInferredOutlives => No, RustcDumpItemBounds => No, + RustcDumpObjectLifetimeDefaults => No, RustcDumpPredicates => No, RustcDumpUserArgs => No, RustcDumpVariances => No, @@ -164,7 +165,6 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { RustcNounwind => No, RustcObjcClass { .. } => No, RustcObjcSelector { .. } => No, - RustcObjectLifetimeDefault => No, RustcOffloadKernel => Yes, RustcParenSugar(..) => No, RustcPassByValue(..) => Yes, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 42c4ff5e7afe..d8e2a8fc18c1 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2119,7 +2119,7 @@ /// Returns the *default lifetime* to be used if a trait object type were to be passed for /// the type parameter given by `DefId`. /// - /// **Tip**: You can use `#[rustc_object_lifetime_default]` on an item to basically + /// **Tip**: You can use `#[rustc_dump_object_lifetime_defaults]` on an item to basically /// print the result of this query for use in UI tests or for debugging purposes. /// /// # Examples diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4d5c793bdd88..3e2f10df20b8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -184,8 +184,8 @@ fn check_attributes( Attribute::Parsed(AttributeKind::TargetFeature{ attr_span, ..}) => { self.check_target_feature(hir_id, *attr_span, target, attrs) } - Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => { - self.check_object_lifetime_default(hir_id); + Attribute::Parsed(AttributeKind::RustcDumpObjectLifetimeDefaults) => { + self.check_dump_object_lifetime_defaults(hir_id); } &Attribute::Parsed(AttributeKind::RustcPubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) @@ -781,8 +781,8 @@ fn check_naked(&self, hir_id: HirId, target: Target) { } } - /// Debugging aid for `object_lifetime_default` query. - fn check_object_lifetime_default(&self, hir_id: HirId) { + /// Debugging aid for the `object_lifetime_default` query. + fn check_dump_object_lifetime_defaults(&self, hir_id: HirId) { let tcx = self.tcx; if let Some(owner_id) = hir_id.as_owner() && let Some(generics) = tcx.hir_get_generics(owner_id.def_id) @@ -796,7 +796,7 @@ fn check_object_lifetime_default(&self, hir_id: HirId) { ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), }; - tcx.dcx().emit_err(errors::ObjectLifetimeErr { span: p.span, repr }); + tcx.dcx().span_err(p.span, repr); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 0cf0d1a5c80f..8073cb257b03 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -814,14 +814,6 @@ pub(crate) struct UselessAssignment<'a> { )] pub(crate) struct InlineIgnoredForExported; -#[derive(Diagnostic)] -#[diag("{$repr}")] -pub(crate) struct ObjectLifetimeErr { - #[primary_span] - pub span: Span, - pub repr: String, -} - #[derive(Diagnostic)] pub(crate) enum AttrApplication { #[diag("attribute should be applied to an enum", code = E0517)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index de486138217d..478a73f86b5f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1723,6 +1723,7 @@ rustc_dump_def_parents, rustc_dump_inferred_outlives, rustc_dump_item_bounds, + rustc_dump_object_lifetime_defaults, rustc_dump_predicates, rustc_dump_user_args, rustc_dump_variances, @@ -1763,7 +1764,6 @@ rustc_nounwind, rustc_objc_class, rustc_objc_selector, - rustc_object_lifetime_default, rustc_offload_kernel, rustc_on_unimplemented, rustc_paren_sugar, diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index d4eb004a0eef..25f7eb27eeea 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -277,12 +277,12 @@ Here are some notable ones: | `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. | | `rustc_dump_inferred_outlives` | Dumps implied bounds of an item. More precisely, the [`inferred_outlives_of`] an item. | | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. | +| `rustc_dump_object_lifetime_defaults` | Dumps the [object lifetime defaults] of an item. | | `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. | | `rustc_dump_variances` | Dumps the [variances] of an item. | | `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. | | `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. | | `rustc_layout` | [See this section](#debugging-type-layouts). | -| `rustc_object_lifetime_default` | Dumps the [object lifetime defaults] of an item. | | `rustc_regions` | Dumps NLL closure region requirements. | | `rustc_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. | diff --git a/tests/ui/object-lifetime/object-lifetime-default.rs b/tests/ui/object-lifetime/object-lifetime-default.rs index 74f5bb7ddb0e..bb1ca509bf67 100644 --- a/tests/ui/object-lifetime/object-lifetime-default.rs +++ b/tests/ui/object-lifetime/object-lifetime-default.rs @@ -1,37 +1,37 @@ #![feature(rustc_attrs)] -#[rustc_object_lifetime_default] +#[rustc_dump_object_lifetime_defaults] struct A< T, //~ ERROR BaseDefault >(T); -#[rustc_object_lifetime_default] +#[rustc_dump_object_lifetime_defaults] struct B< 'a, T, //~ ERROR BaseDefault >(&'a (), T); -#[rustc_object_lifetime_default] +#[rustc_dump_object_lifetime_defaults] struct C< 'a, T: 'a, //~ ERROR 'a >(&'a T); -#[rustc_object_lifetime_default] +#[rustc_dump_object_lifetime_defaults] struct D< 'a, 'b, T: 'a + 'b, //~ ERROR Ambiguous >(&'a T, &'b T); -#[rustc_object_lifetime_default] +#[rustc_dump_object_lifetime_defaults] struct E< 'a, 'b: 'a, T: 'b, //~ ERROR 'b >(&'a T, &'b T); -#[rustc_object_lifetime_default] +#[rustc_dump_object_lifetime_defaults] struct F< 'a, 'b, @@ -39,7 +39,7 @@ struct F< U: 'b, //~ ERROR 'b >(&'a T, &'b U); -#[rustc_object_lifetime_default] +#[rustc_dump_object_lifetime_defaults] struct G< 'a, 'b, From dc3db2373c2b5f5853dea973e4ce3c30686534f4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:18:25 +0000 Subject: [PATCH 36/59] Slightly simplify write_bitcode_to_file handling This also causes bitcode to be saved for the allocator shim with -Csave-temps. --- compiler/rustc_codegen_llvm/src/back/write.rs | 15 +++++---------- compiler/rustc_codegen_ssa/src/back/write.rs | 2 -- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index d7ab1356fafe..efd4e55d5a85 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -335,13 +335,13 @@ pub(crate) fn save_temp_bitcode( &module.name, cgcx.invocation_temp.as_deref(), ); - write_bitcode_to_file(module, &path) + write_bitcode_to_file(&module.module_llvm, &path) } -fn write_bitcode_to_file(module: &ModuleCodegen, path: &Path) { +fn write_bitcode_to_file(module: &ModuleLlvm, path: &Path) { unsafe { let path = path_to_c_string(&path); - let llmod = module.module_llvm.llmod(); + let llmod = module.llmod(); llvm::LLVMWriteBitcodeToFile(llmod, path.as_ptr()); } } @@ -905,13 +905,8 @@ pub(crate) fn optimize( let _handlers = DiagnosticHandlers::new(cgcx, shared_emitter, llcx, module, CodegenDiagnosticsStage::Opt); - if config.emit_no_opt_bc { - let out = cgcx.output_filenames.temp_path_ext_for_cgu( - "no-opt.bc", - &module.name, - cgcx.invocation_temp.as_deref(), - ); - write_bitcode_to_file(module, &out) + if module.kind == ModuleKind::Regular { + save_temp_bitcode(cgcx, module, "no-opt"); } // FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0d210eacf9a8..f1a6d9bd1050 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -94,7 +94,6 @@ pub struct ModuleConfig { // Flags indicating which outputs to produce. pub emit_pre_lto_bc: bool, - pub emit_no_opt_bc: bool, pub emit_bc: bool, pub emit_ir: bool, pub emit_asm: bool, @@ -195,7 +194,6 @@ macro_rules! if_regular { save_temps || need_pre_lto_bitcode_for_incr_comp(sess), false ), - emit_no_opt_bc: if_regular!(save_temps, false), emit_bc: if_regular!( save_temps || sess.opts.output_types.contains_key(&OutputType::Bitcode), save_temps From 9e917ee7a6c4694b243829a692d3b02b125a6da1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:12:35 +0000 Subject: [PATCH 37/59] Replace spawn_named_thread method with thread_profiler --- compiler/rustc_codegen_llvm/src/lib.rs | 32 ++++--------------- compiler/rustc_codegen_ssa/src/back/write.rs | 29 +++++++++++------ .../rustc_codegen_ssa/src/traits/backend.rs | 13 ++------ 3 files changed, 29 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index c03b0ac9157a..2c5f283e1e9a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -79,24 +79,18 @@ #[derive(Clone)] pub struct LlvmCodegenBackend(()); -struct TimeTraceProfiler { - enabled: bool, -} +struct TimeTraceProfiler {} impl TimeTraceProfiler { - fn new(enabled: bool) -> Self { - if enabled { - unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() } - } - TimeTraceProfiler { enabled } + fn new() -> Self { + unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() } + TimeTraceProfiler {} } } impl Drop for TimeTraceProfiler { fn drop(&mut self) { - if self.enabled { - unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() } - } + unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() } } } @@ -131,20 +125,8 @@ fn target_machine_factory( back::write::target_machine_factory(sess, optlvl, target_features) } - fn spawn_named_thread( - time_trace: bool, - name: String, - f: F, - ) -> std::io::Result> - where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, - { - std::thread::Builder::new().name(name).spawn(move || { - let _profiler = TimeTraceProfiler::new(time_trace); - f() - }) + fn thread_profiler() -> Box { + Box::new(TimeTraceProfiler::new()) } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index f1a6d9bd1050..b1b5da7da8b4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1470,7 +1470,9 @@ fn start_executing_work( // Each LLVM module is automatically sent back to the coordinator for LTO if // necessary. There's already optimizations in place to avoid sending work // back to the coordinator if LTO isn't requested. - return B::spawn_named_thread(cgcx.time_trace, "coordinator".to_string(), move || { + let f = move || { + let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; + // This is where we collect codegen units that have gone all the way // through codegen and LLVM. let mut compiled_modules = vec![]; @@ -1811,8 +1813,11 @@ enum CodegenState { B::codegen(&cgcx, &prof, &shared_emitter, allocator_module, &allocator_config) }), })) - }) - .expect("failed to spawn coordinator thread"); + }; + return std::thread::Builder::new() + .name("coordinator".to_owned()) + .spawn(f) + .expect("failed to spawn coordinator thread"); // A heuristic that determines if we have enough LLVM WorkItems in the // queue so that the main thread can do LLVM work instead of codegen @@ -1891,7 +1896,10 @@ fn spawn_work<'a, B: ExtraBackendMethods>( let cgcx = cgcx.clone(); let prof = prof.clone(); - B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { + let name = work.short_description(); + let f = move || { + let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; + let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, &prof, shared_emitter, m), WorkItem::CopyPostLtoArtifacts(m) => WorkItemResult::Finished( @@ -1912,8 +1920,8 @@ fn spawn_work<'a, B: ExtraBackendMethods>( Err(_) => Message::WorkItem:: { result: Err(None) }, }; drop(coordinator_send.send(msg)); - }) - .expect("failed to spawn work thread"); + }; + std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread"); } fn spawn_thin_lto_work( @@ -1927,7 +1935,10 @@ fn spawn_thin_lto_work( let cgcx = cgcx.clone(); let prof = prof.clone(); - B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { + let name = work.short_description(); + let f = move || { + let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; + let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { ThinLtoWorkItem::CopyPostLtoArtifacts(m) => { execute_copy_from_cache_work_item(&cgcx, &prof, shared_emitter, m) @@ -1950,8 +1961,8 @@ fn spawn_thin_lto_work( Err(_) => ThinLtoMessage::WorkItem { result: Err(None) }, }; drop(coordinator_send.send(msg)); - }) - .expect("failed to spawn work thread"); + }; + std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread"); } enum SharedEmitterMessage { diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 8df1ecc0fff5..776f7cde6c98 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -165,17 +165,8 @@ fn target_machine_factory( target_features: &[String], ) -> TargetMachineFactoryFn; - fn spawn_named_thread( - _time_trace: bool, - name: String, - f: F, - ) -> std::io::Result> - where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, - { - std::thread::Builder::new().name(name).spawn(f) + fn thread_profiler() -> Box { + Box::new(()) } /// Returns `true` if this backend can be safely called from multiple threads. From 22d4bb25925221d011b8573e6cbd88f5c3b036e4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:31:51 +0000 Subject: [PATCH 38/59] Move print_pass_timings and print_statistics calls to rustc_interface --- compiler/rustc_codegen_gcc/src/lib.rs | 8 -------- compiler/rustc_codegen_llvm/src/lib.rs | 18 ++++++++++-------- compiler/rustc_codegen_ssa/src/back/write.rs | 10 ---------- .../rustc_codegen_ssa/src/traits/backend.rs | 4 ++++ compiler/rustc_codegen_ssa/src/traits/write.rs | 2 -- compiler/rustc_interface/src/queries.rs | 9 +++++++++ 6 files changed, 23 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 529a5085c30f..3409c0e02340 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -455,14 +455,6 @@ fn run_thin_lto( unreachable!() } - fn print_pass_timings(&self) { - unimplemented!(); - } - - fn print_statistics(&self) { - unimplemented!() - } - fn optimize( _cgcx: &CodegenContext, _prof: &SelfProfilerRef, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 2c5f283e1e9a..46b26832d207 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -135,14 +135,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { type ModuleBuffer = back::lto::ModuleBuffer; type TargetMachine = OwnedTargetMachine; type ThinData = back::lto::ThinData; - fn print_pass_timings(&self) { - let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); - print!("{timings}"); - } - fn print_statistics(&self) { - let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap(); - print!("{stats}"); - } fn run_and_optimize_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, @@ -371,6 +363,16 @@ fn join_codegen( (compiled_modules, work_products) } + fn print_pass_timings(&self) { + let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); + print!("{timings}"); + } + + fn print_statistics(&self) { + let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap(); + print!("{stats}"); + } + fn link( &self, sess: &Session, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index b1b5da7da8b4..55951fde62f6 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -2243,16 +2243,6 @@ pub fn join(self, sess: &Session) -> (CompiledModules, FxIndexMap (CompiledModules, FxIndexMap); + fn print_pass_timings(&self) {} + + fn print_statistics(&self) {} + /// This is called on the returned [`CompiledModules`] from [`join_codegen`](Self::join_codegen). fn link( &self, diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index d33dfc1d014b..89bb1e6e88d5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -39,8 +39,6 @@ fn run_thin_lto( modules: Vec<(String, Self::ModuleBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec); - fn print_pass_timings(&self); - fn print_statistics(&self); fn optimize( cgcx: &CodegenContext, prof: &SelfProfilerRef, diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index f4fcd4471d3f..170393f3b817 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -58,6 +58,15 @@ pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) { } } }); + + if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes { + codegen_backend.print_pass_timings() + } + + if sess.print_llvm_stats() { + codegen_backend.print_statistics() + } + sess.timings.end_section(sess.dcx(), TimingSection::Codegen); if sess.opts.incremental.is_some() From eff0d4c6f4c5e8f9f88d43180cd83ba5e913c2da Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:52:46 +0000 Subject: [PATCH 39/59] Fuse codegen into LTO optimize methods --- compiler/rustc_codegen_gcc/src/back/lto.rs | 12 ++++++------ compiler/rustc_codegen_gcc/src/back/write.rs | 11 +++-------- compiler/rustc_codegen_gcc/src/lib.rs | 14 ++++++++------ compiler/rustc_codegen_llvm/src/back/lto.rs | 11 ++++++----- compiler/rustc_codegen_llvm/src/lib.rs | 12 ++++++------ compiler/rustc_codegen_ssa/src/back/write.rs | 8 +++----- compiler/rustc_codegen_ssa/src/traits/write.rs | 8 ++++---- 7 files changed, 36 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index a08e3dc0df87..347a15a392af 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -26,7 +26,7 @@ use rustc_codegen_ssa::back::lto::SerializedModule; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::{DiagCtxt, DiagCtxtHandle}; @@ -34,7 +34,7 @@ use rustc_session::config::Lto; use tempfile::{TempDir, tempdir}; -use crate::back::write::save_temp_bitcode; +use crate::back::write::{codegen, save_temp_bitcode}; use crate::errors::LtoBitcodeFromRlib; use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; @@ -112,7 +112,7 @@ pub(crate) fn run_fat( shared_emitter: &SharedEmitter, each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, -) -> ModuleCodegen { +) -> CompiledModule { let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); @@ -132,12 +132,12 @@ pub(crate) fn run_fat( fn fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, - _dcx: DiagCtxtHandle<'_>, + dcx: DiagCtxtHandle<'_>, modules: Vec>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> ModuleCodegen { +) -> CompiledModule { let _timer = prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -260,7 +260,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - module + codegen(cgcx, prof, dcx, module, &cgcx.module_config) } pub struct ModuleBuffer(PathBuf); diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index ddf13558027b..24ea2b66ba7d 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -2,12 +2,10 @@ use gccjit::{Context, OutputKind}; use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::write::{ - BitcodeSection, CodegenContext, EmitObj, ModuleConfig, SharedEmitter, -}; +use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_fs_util::link_or_copy; use rustc_log::tracing::debug; use rustc_session::config::OutputType; @@ -20,13 +18,10 @@ pub(crate) fn codegen( cgcx: &CodegenContext, prof: &SelfProfilerRef, - shared_emitter: &SharedEmitter, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); - let dcx = dcx.handle(); - let _timer = prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 3409c0e02340..ed809eb33a53 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -92,7 +92,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; @@ -429,7 +429,7 @@ impl WriteBackendMethods for GccCodegenBackend { type ModuleBuffer = ModuleBuffer; type ThinData = (); - fn run_and_optimize_fat_lto( + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, @@ -438,7 +438,7 @@ fn run_and_optimize_fat_lto( _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - ) -> ModuleCodegen { + ) -> CompiledModule { back::lto::run_fat(cgcx, prof, shared_emitter, each_linked_rlib_for_lto, modules) } @@ -465,13 +465,13 @@ fn optimize( module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); } - fn optimize_thin( + fn optimize_and_codegen_thin( _cgcx: &CodegenContext, _prof: &SelfProfilerRef, _shared_emitter: &SharedEmitter, _tm_factory: TargetMachineFactoryFn, _thin: ThinModule, - ) -> ModuleCodegen { + ) -> CompiledModule { unreachable!() } @@ -482,7 +482,9 @@ fn codegen( module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - back::write::codegen(cgcx, prof, shared_emitter, module, config) + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + let dcx = dcx.handle(); + back::write::codegen(cgcx, prof, dcx, module, config) } fn serialize_module(_module: Self::Module, _is_thin: bool) -> Self::ModuleBuffer { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index c235437aee75..f6cd229cb106 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -12,7 +12,7 @@ CodegenContext, FatLtoInput, SharedEmitter, TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; @@ -24,7 +24,8 @@ use tracing::{debug, info}; use crate::back::write::{ - self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, save_temp_bitcode, + self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, codegen, + save_temp_bitcode, }; use crate::errors::{LlvmError, LtoBitcodeFromRlib}; use crate::llvm::{self, build_string}; @@ -709,13 +710,13 @@ fn data(&self) -> &[u8] { } } -pub(crate) fn optimize_thin_module( +pub(crate) fn optimize_and_codegen_thin_module( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, thin_module: ThinModule, -) -> ModuleCodegen { +) -> CompiledModule { let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); @@ -794,7 +795,7 @@ pub(crate) fn optimize_thin_module( save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } } - module + codegen(cgcx, prof, shared_emitter, module, &cgcx.module_config) } /// Maps LLVM module identifiers to their corresponding LLVM LTO cache keys diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 46b26832d207..cda1e470fce4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -135,7 +135,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { type ModuleBuffer = back::lto::ModuleBuffer; type TargetMachine = OwnedTargetMachine; type ThinData = back::lto::ThinData; - fn run_and_optimize_fat_lto( + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, @@ -143,7 +143,7 @@ fn run_and_optimize_fat_lto( exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - ) -> ModuleCodegen { + ) -> CompiledModule { let mut module = back::lto::run_fat( cgcx, prof, @@ -158,7 +158,7 @@ fn run_and_optimize_fat_lto( let dcx = dcx.handle(); back::lto::run_pass_manager(cgcx, prof, dcx, &mut module, false); - module + back::write::codegen(cgcx, prof, shared_emitter, module, &cgcx.module_config) } fn run_thin_lto( cgcx: &CodegenContext, @@ -188,14 +188,14 @@ fn optimize( ) { back::write::optimize(cgcx, prof, shared_emitter, module, config) } - fn optimize_thin( + fn optimize_and_codegen_thin( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, thin: ThinModule, - ) -> ModuleCodegen { - back::lto::optimize_thin_module(cgcx, prof, shared_emitter, tm_factory, thin) + ) -> CompiledModule { + back::lto::optimize_and_codegen_thin_module(cgcx, prof, shared_emitter, tm_factory, thin) } fn codegen( cgcx: &CodegenContext, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 55951fde62f6..31a77952ea38 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -988,7 +988,7 @@ fn do_fat_lto( needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) } - let module = B::run_and_optimize_fat_lto( + B::optimize_and_codegen_fat_lto( cgcx, prof, &shared_emitter, @@ -996,8 +996,7 @@ fn do_fat_lto( exported_symbols_for_lto, each_linked_rlib_for_lto, needs_fat_lto, - ); - B::codegen(cgcx, prof, &shared_emitter, module, &cgcx.module_config) + ) } fn do_thin_lto( @@ -1162,8 +1161,7 @@ fn execute_thin_lto_work_item( ) -> CompiledModule { let _timer = prof.generic_activity_with_arg("codegen_module_perform_lto", module.name()); - let module = B::optimize_thin(cgcx, prof, &shared_emitter, tm_factory, module); - B::codegen(cgcx, prof, &shared_emitter, module, &cgcx.module_config) + B::optimize_and_codegen_thin(cgcx, prof, &shared_emitter, tm_factory, module) } /// Messages sent to the coordinator. diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 89bb1e6e88d5..d218b0f31722 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -18,7 +18,7 @@ pub trait WriteBackendMethods: Clone + 'static { /// Performs fat LTO by merging all modules into a single one, running autodiff /// if necessary and running any further optimizations - fn run_and_optimize_fat_lto( + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, @@ -26,7 +26,7 @@ fn run_and_optimize_fat_lto( exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - ) -> ModuleCodegen; + ) -> CompiledModule; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that /// can simply be copied over from the incr. comp. cache. @@ -46,13 +46,13 @@ fn optimize( module: &mut ModuleCodegen, config: &ModuleConfig, ); - fn optimize_thin( + fn optimize_and_codegen_thin( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, thin: ThinModule, - ) -> ModuleCodegen; + ) -> CompiledModule; fn codegen( cgcx: &CodegenContext, prof: &SelfProfilerRef, From 6ea5244ebf7589720a32474de9410e9bc73981eb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:38:39 +0000 Subject: [PATCH 40/59] Move some methods to WriteBackendMethods --- compiler/rustc_codegen_gcc/src/lib.rs | 20 ++++++------- compiler/rustc_codegen_llvm/src/lib.rs | 21 +++++++------ compiler/rustc_codegen_ssa/src/back/write.rs | 30 +++++++++---------- .../rustc_codegen_ssa/src/traits/backend.rs | 14 +-------- .../rustc_codegen_ssa/src/traits/write.rs | 11 +++++++ 5 files changed, 47 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index ed809eb33a53..592eb68ce275 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -371,16 +371,6 @@ fn compile_codegen_unit( self.lto_supported.load(Ordering::SeqCst), ) } - - fn target_machine_factory( - &self, - _sess: &Session, - _opt_level: OptLevel, - _features: &[String], - ) -> TargetMachineFactoryFn { - // TODO(antoyo): set opt level. - Arc::new(|_, _| ()) - } } #[derive(Clone, Copy, PartialEq)] @@ -429,6 +419,16 @@ impl WriteBackendMethods for GccCodegenBackend { type ModuleBuffer = ModuleBuffer; type ThinData = (); + fn target_machine_factory( + &self, + _sess: &Session, + _opt_level: OptLevel, + _features: &[String], + ) -> TargetMachineFactoryFn { + // TODO(antoyo): set opt level. + Arc::new(|_, _| ()) + } + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index cda1e470fce4..62bba6c9bfc2 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -116,6 +116,16 @@ fn compile_codegen_unit( ) -> (ModuleCodegen, u64) { base::compile_codegen_unit(tcx, cgu_name) } +} + +impl WriteBackendMethods for LlvmCodegenBackend { + type Module = ModuleLlvm; + type ModuleBuffer = back::lto::ModuleBuffer; + type TargetMachine = OwnedTargetMachine; + type ThinData = back::lto::ThinData; + fn thread_profiler() -> Box { + Box::new(TimeTraceProfiler::new()) + } fn target_machine_factory( &self, sess: &Session, @@ -124,17 +134,6 @@ fn target_machine_factory( ) -> TargetMachineFactoryFn { back::write::target_machine_factory(sess, optlvl, target_features) } - - fn thread_profiler() -> Box { - Box::new(TimeTraceProfiler::new()) - } -} - -impl WriteBackendMethods for LlvmCodegenBackend { - type Module = ModuleLlvm; - type ModuleBuffer = back::lto::ModuleBuffer; - type TargetMachine = OwnedTargetMachine; - type ThinData = back::lto::ThinData; fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 31a77952ea38..3734e273e0b5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -354,7 +354,7 @@ pub struct CodegenContext { pub parallel: bool, } -fn generate_thin_lto_work( +fn generate_thin_lto_work( cgcx: &CodegenContext, prof: &SelfProfilerRef, dcx: DiagCtxtHandle<'_>, @@ -822,7 +822,7 @@ pub(crate) fn compute_per_cgu_lto_type( } } -fn execute_optimize_work_item( +fn execute_optimize_work_item( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -967,7 +967,7 @@ fn execute_copy_from_cache_work_item( } } -fn do_fat_lto( +fn do_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -999,7 +999,7 @@ fn do_fat_lto( ) } -fn do_thin_lto( +fn do_thin_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -1152,7 +1152,7 @@ fn do_thin_lto( compiled_modules } -fn execute_thin_lto_work_item( +fn execute_thin_lto_work_item( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -1879,7 +1879,7 @@ fn queue_full_enough(items_in_queue: usize, workers_running: usize) -> bool { #[must_use] pub(crate) struct WorkerFatalError; -fn spawn_work<'a, B: ExtraBackendMethods>( +fn spawn_work<'a, B: WriteBackendMethods>( cgcx: &CodegenContext, prof: &'a SelfProfilerRef, shared_emitter: SharedEmitter, @@ -1922,7 +1922,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread"); } -fn spawn_thin_lto_work( +fn spawn_thin_lto_work( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -2109,20 +2109,20 @@ fn check(&self, sess: &Session, blocking: bool) { } } -pub struct Coordinator { +pub struct Coordinator { sender: Sender>, future: Option, ()>>>, // Only used for the Message type. phantom: PhantomData, } -impl Coordinator { +impl Coordinator { fn join(mut self) -> std::thread::Result, ()>> { self.future.take().unwrap().join() } } -impl Drop for Coordinator { +impl Drop for Coordinator { fn drop(&mut self) { if let Some(future) = self.future.take() { // If we haven't joined yet, signal to the coordinator that it should spawn no more @@ -2133,7 +2133,7 @@ fn drop(&mut self) { } } -pub struct OngoingCodegen { +pub struct OngoingCodegen { pub backend: B, pub output_filenames: Arc, // Field order below is intended to terminate the coordinator thread before two fields below @@ -2144,7 +2144,7 @@ pub struct OngoingCodegen { pub shared_emitter_main: SharedEmitterMain, } -impl OngoingCodegen { +impl OngoingCodegen { pub fn join(self, sess: &Session) -> (CompiledModules, FxIndexMap) { self.shared_emitter_main.check(sess, true); @@ -2267,7 +2267,7 @@ pub(crate) fn wait_for_signal_to_codegen_item(&self) { } } -pub(crate) fn submit_codegened_module_to_llvm( +pub(crate) fn submit_codegened_module_to_llvm( coordinator: &Coordinator, module: ModuleCodegen, cost: u64, @@ -2276,7 +2276,7 @@ pub(crate) fn submit_codegened_module_to_llvm( drop(coordinator.sender.send(Message::CodegenDone:: { llvm_work_item, cost })); } -pub(crate) fn submit_post_lto_module_to_llvm( +pub(crate) fn submit_post_lto_module_to_llvm( coordinator: &Coordinator, module: CachedModuleCodegen, ) { @@ -2284,7 +2284,7 @@ pub(crate) fn submit_post_lto_module_to_llvm( drop(coordinator.sender.send(Message::CodegenDone:: { llvm_work_item, cost: 0 })); } -pub(crate) fn submit_pre_lto_module_to_llvm( +pub(crate) fn submit_pre_lto_module_to_llvm( tcx: TyCtxt<'_>, coordinator: &Coordinator, module: CachedModuleCodegen, diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 5b0275b0d1df..7b95562ddda3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -10,14 +10,13 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; -use rustc_session::config::{self, CrateType, OutputFilenames, PrintRequest}; +use rustc_session::config::{CrateType, OutputFilenames, PrintRequest}; use rustc_span::Symbol; use super::CodegenObject; use super::write::WriteBackendMethods; use crate::back::archive::ArArchiveBuilderBuilder; use crate::back::link::link_binary; -use crate::back::write::TargetMachineFactoryFn; use crate::{CompiledModules, CrateInfo, ModuleCodegen, TargetConfig}; pub trait BackendTypes { @@ -162,17 +161,6 @@ fn compile_codegen_unit( cgu_name: Symbol, ) -> (ModuleCodegen, u64); - fn target_machine_factory( - &self, - sess: &Session, - opt_level: config::OptLevel, - target_features: &[String], - ) -> TargetMachineFactoryFn; - - fn thread_profiler() -> Box { - Box::new(()) - } - /// Returns `true` if this backend can be safely called from multiple threads. /// /// Defaults to `true`. diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index d218b0f31722..5d2313092fa8 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -1,8 +1,10 @@ +use std::any::Any; use std::path::PathBuf; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::DiagCtxtHandle; use rustc_middle::dep_graph::WorkProduct; +use rustc_session::{Session, config}; use crate::back::lto::{SerializedModule, ThinModule}; use crate::back::write::{ @@ -16,6 +18,15 @@ pub trait WriteBackendMethods: Clone + 'static { type ModuleBuffer: ModuleBufferMethods; type ThinData: Send + Sync; + fn thread_profiler() -> Box { + Box::new(()) + } + fn target_machine_factory( + &self, + sess: &Session, + opt_level: config::OptLevel, + target_features: &[String], + ) -> TargetMachineFactoryFn; /// Performs fat LTO by merging all modules into a single one, running autodiff /// if necessary and running any further optimizations fn optimize_and_codegen_fat_lto( From 52b4de34ec837c09e0ec4c1ce9f00ce8e8b032f8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 27 Feb 2026 17:03:27 +1100 Subject: [PATCH 41/59] Abort after printing infinite type errors. Currently, `Representability::from_cycle_error` prints an "infinite size" error and then returns `Representability::Infinite`, which lets analysis continue. This commit changes it so it just aborts after printing the error. This has two benefits. First, the error messages are better. The error messages we get after continuing are mostly bad -- we usually get another cycle error, e.g. about drop checking or layout, which is not much use to the user, and then abort after that. The only exception is `issue-105231.rs` where a "conflicting implementations" error is now omitted, but there are three other errors before that one so it's no great loss. Second, it allows some simplifications: see the next commit. --- .../rustc_query_impl/src/from_cycle_error.rs | 4 ++- tests/ui/enum-discriminant/issue-72554.rs | 1 - tests/ui/enum-discriminant/issue-72554.stderr | 21 +++------------ tests/ui/infinite/infinite-struct.rs | 2 -- tests/ui/infinite/infinite-struct.stderr | 25 +++--------------- .../infinite/infinite-tag-type-recursion.rs | 1 - .../infinite-tag-type-recursion.stderr | 15 ++--------- .../query-cycle-printing-issue-151226.rs | 2 -- .../query-cycle-printing-issue-151226.stderr | 26 ++----------------- .../structs-enums/enum-rec/issue-17431-6.rs | 1 - .../enum-rec/issue-17431-6.stderr | 15 ++--------- tests/ui/traits/issue-105231.rs | 1 - tests/ui/traits/issue-105231.stderr | 16 ++---------- .../transmute_infinitely_recursive_type.rs | 1 - ...transmute_infinitely_recursive_type.stderr | 13 +++------- 15 files changed, 20 insertions(+), 124 deletions(-) diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index a13db9004d67..328bd4a02c8f 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -117,8 +117,10 @@ fn from_cycle_error( representable_ids.insert(def_id); } } + // We used to continue here, but the cycle error printed next is actually less useful than + // the error produced by `recursive_type_error`. let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); - Representability::Infinite(guar) + guar.raise_fatal(); } } diff --git a/tests/ui/enum-discriminant/issue-72554.rs b/tests/ui/enum-discriminant/issue-72554.rs index 1fe9a5f4faa7..54f7e9ac592e 100644 --- a/tests/ui/enum-discriminant/issue-72554.rs +++ b/tests/ui/enum-discriminant/issue-72554.rs @@ -3,7 +3,6 @@ #[derive(Hash)] pub enum ElemDerived { //~^ ERROR recursive type `ElemDerived` has infinite size - //~| ERROR cycle detected A(ElemDerived) } diff --git a/tests/ui/enum-discriminant/issue-72554.stderr b/tests/ui/enum-discriminant/issue-72554.stderr index 648680c6031d..381f24d351e9 100644 --- a/tests/ui/enum-discriminant/issue-72554.stderr +++ b/tests/ui/enum-discriminant/issue-72554.stderr @@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size | LL | pub enum ElemDerived { | ^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | A(ElemDerived) | ----------- recursive without indirection | @@ -12,21 +12,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | A(Box) | ++++ + -error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived` - --> $DIR/issue-72554.rs:4:1 - | -LL | pub enum ElemDerived { - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again -note: cycle used when computing drop-check constraints for `Elem` - --> $DIR/issue-72554.rs:11:1 - | -LL | pub enum Elem { - | ^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/infinite/infinite-struct.rs b/tests/ui/infinite/infinite-struct.rs index d78445582460..f08e10f6bdbc 100644 --- a/tests/ui/infinite/infinite-struct.rs +++ b/tests/ui/infinite/infinite-struct.rs @@ -1,7 +1,5 @@ struct Take(Take); //~^ ERROR has infinite size -//~| ERROR cycle -//~| ERROR reached the recursion limit finding the struct tail for `Take` // check that we don't hang trying to find the tail of a recursive struct (#79437) fn foo() -> Take { diff --git a/tests/ui/infinite/infinite-struct.stderr b/tests/ui/infinite/infinite-struct.stderr index 0d1ec4989aa5..b6c72b1de469 100644 --- a/tests/ui/infinite/infinite-struct.stderr +++ b/tests/ui/infinite/infinite-struct.stderr @@ -10,7 +10,7 @@ LL | struct Take(Box); | ++++ + error[E0072]: recursive type `Foo` has infinite size - --> $DIR/infinite-struct.rs:12:1 + --> $DIR/infinite-struct.rs:10:1 | LL | struct Foo { | ^^^^^^^^^^ @@ -22,25 +22,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | x: Bar>, | ++++ + -error: reached the recursion limit finding the struct tail for `Take` - --> $DIR/infinite-struct.rs:1:1 - | -LL | struct Take(Take); - | ^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` +error: aborting due to 2 previous errors -error[E0391]: cycle detected when computing when `Take` needs drop - --> $DIR/infinite-struct.rs:1:1 - | -LL | struct Take(Take); - | ^^^^^^^^^^^ - | - = note: ...which immediately requires computing when `Take` needs drop again - = note: cycle used when computing whether `Take` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/infinite/infinite-tag-type-recursion.rs b/tests/ui/infinite/infinite-tag-type-recursion.rs index 1b5cb55b4e4d..87a9e08dd381 100644 --- a/tests/ui/infinite/infinite-tag-type-recursion.rs +++ b/tests/ui/infinite/infinite-tag-type-recursion.rs @@ -1,5 +1,4 @@ enum MList { Cons(isize, MList), Nil } //~^ ERROR recursive type `MList` has infinite size -//~| ERROR cycle fn main() { let a = MList::Cons(10, MList::Cons(11, MList::Nil)); } diff --git a/tests/ui/infinite/infinite-tag-type-recursion.stderr b/tests/ui/infinite/infinite-tag-type-recursion.stderr index 8745224a45e1..4ca408260b84 100644 --- a/tests/ui/infinite/infinite-tag-type-recursion.stderr +++ b/tests/ui/infinite/infinite-tag-type-recursion.stderr @@ -9,17 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | enum MList { Cons(isize, Box), Nil } | ++++ + -error[E0391]: cycle detected when computing when `MList` needs drop - --> $DIR/infinite-tag-type-recursion.rs:1:1 - | -LL | enum MList { Cons(isize, MList), Nil } - | ^^^^^^^^^^ - | - = note: ...which immediately requires computing when `MList` needs drop again - = note: cycle used when computing whether `MList` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/query-system/query-cycle-printing-issue-151226.rs b/tests/ui/query-system/query-cycle-printing-issue-151226.rs index 9d0a20737c9f..551321619ddd 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151226.rs +++ b/tests/ui/query-system/query-cycle-printing-issue-151226.rs @@ -1,8 +1,6 @@ struct A(std::sync::OnceLock); //~^ ERROR recursive type `A` has infinite size -//~| ERROR cycle detected when computing layout of `A<()>` static B: A<()> = todo!(); -//~^ ERROR cycle occurred during layout computation fn main() {} diff --git a/tests/ui/query-system/query-cycle-printing-issue-151226.stderr b/tests/ui/query-system/query-cycle-printing-issue-151226.stderr index 7e574b5911a3..bb05cf5f915d 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151226.stderr +++ b/tests/ui/query-system/query-cycle-printing-issue-151226.stderr @@ -9,28 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | struct A(Box>); | ++++ + -error[E0391]: cycle detected when computing layout of `A<()>` - | - = note: ...which requires computing layout of `std::sync::once_lock::OnceLock>`... - = note: ...which requires computing layout of `core::cell::UnsafeCell>>`... - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit>`... - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop>`... - = note: ...which requires computing layout of `core::mem::maybe_dangling::MaybeDangling>`... - = note: ...which again requires computing layout of `A<()>`, completing the cycle -note: cycle used when checking that `B` is well-formed - --> $DIR/query-cycle-printing-issue-151226.rs:5:1 - | -LL | static B: A<()> = todo!(); - | ^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 1 previous error -error[E0080]: a cycle occurred during layout computation - --> $DIR/query-cycle-printing-issue-151226.rs:5:1 - | -LL | static B: A<()> = todo!(); - | ^^^^^^^^^^^^^^^ evaluation of `B` failed here - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0072, E0080, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs index a3b510848dcd..c89b69d3c2f2 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs @@ -2,7 +2,6 @@ enum Foo { X(UnsafeCell>) } //~^ ERROR recursive type `Foo` has infinite size -//~| ERROR cycle detected impl Foo { fn bar(self) {} } diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr index b192593d266b..8939b603c798 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr @@ -9,17 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | enum Foo { X(UnsafeCell>>) } | ++++ + -error[E0391]: cycle detected when computing when `Foo` needs drop - --> $DIR/issue-17431-6.rs:3:1 - | -LL | enum Foo { X(UnsafeCell>) } - | ^^^^^^^^ - | - = note: ...which immediately requires computing when `Foo` needs drop again - = note: cycle used when computing whether `Foo` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/traits/issue-105231.rs b/tests/ui/traits/issue-105231.rs index 83c3158c106b..9e47ded7c8c8 100644 --- a/tests/ui/traits/issue-105231.rs +++ b/tests/ui/traits/issue-105231.rs @@ -6,5 +6,4 @@ trait Foo {} impl Foo for T where T: Send {} impl Foo for B {} -//~^ ERROR conflicting implementations of trait `Foo` for type `B` fn main() {} diff --git a/tests/ui/traits/issue-105231.stderr b/tests/ui/traits/issue-105231.stderr index b048548018a7..6732d4f5803c 100644 --- a/tests/ui/traits/issue-105231.stderr +++ b/tests/ui/traits/issue-105231.stderr @@ -37,18 +37,6 @@ LL | struct B(A>); = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = note: all type parameters must be used in a non-recursive way in order to constrain their variance -error[E0119]: conflicting implementations of trait `Foo` for type `B` - --> $DIR/issue-105231.rs:8:1 - | -LL | impl Foo for T where T: Send {} - | ------------------------------- first implementation here -LL | impl Foo for B {} - | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `B` - | - = note: overflow evaluating the requirement `B: Send` - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_105231`) +error: aborting due to 3 previous errors -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0072, E0119. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs index 8d291054365f..d3a6ba94b68f 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -1,4 +1,3 @@ -//~ ERROR: cycle detected //! Safe transmute did not handle cycle errors that could occur during //! layout computation. This test checks that we do not ICE in such //! situations (see #117491). diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index a96876a2c25a..0b5689e1912f 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -1,5 +1,5 @@ error[E0072]: recursive type `ExplicitlyPadded` has infinite size - --> $DIR/transmute_infinitely_recursive_type.rs:21:5 + --> $DIR/transmute_infinitely_recursive_type.rs:20:5 | LL | struct ExplicitlyPadded(ExplicitlyPadded); | ^^^^^^^^^^^^^^^^^^^^^^^ ---------------- recursive without indirection @@ -9,13 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | struct ExplicitlyPadded(Box); | ++++ + -error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` - | - = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again - = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information +error: aborting due to 1 previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. From ff3d308966724fb33303fd9a474027297a43f832 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 27 Feb 2026 17:38:59 +1100 Subject: [PATCH 42/59] Eliminate `Representability::Infinite`. This variant was a fallback value used to continue analysis after a `Representability` error, but it's no longer needed thanks to the previous commit. This means `Representability` can now be reduced to a unit type that exists just so `FromCycleError` can exist for the `representability` query. (There is potential for additional cleanups here, but those are beyond the scope of this PR.) This means the `representability`/`representability_adt_ty` queries no longer have a meaningful return value, i.e. they are check-only queries. So they now have a `check_` prefix added. And the `rtry!` macro is no longer needed. --- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_middle/src/queries.rs | 17 ++-- compiler/rustc_middle/src/ty/adt.rs | 7 +- .../rustc_middle/src/ty/inhabitedness/mod.rs | 5 +- .../rustc_query_impl/src/from_cycle_error.rs | 4 +- .../rustc_ty_utils/src/representability.rs | 82 ++++++++++--------- compiler/rustc_ty_utils/src/ty.rs | 7 +- 7 files changed, 64 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0b6165c02bab..38025f74b2f6 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -997,7 +997,7 @@ fn check_type_defn<'tcx>( item: &hir::Item<'tcx>, all_sized: bool, ) -> Result<(), ErrorGuaranteed> { - let _ = tcx.representability(item.owner_id.def_id); + let _ = tcx.check_representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| { diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 932d0855c601..4c7d68ebd3e0 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -593,18 +593,23 @@ } /// Checks whether a type is representable or infinitely sized - query representability(key: LocalDefId) -> rustc_middle::ty::Representability { + query check_representability(key: LocalDefId) -> rustc_middle::ty::Representability { desc { "checking if `{}` is representable", tcx.def_path_str(key) } - // infinitely sized types will cause a cycle + // Infinitely sized types will cause a cycle. The custom `FromCycleError` impl for + // `Representability` will print a custom error about the infinite size and then abort + // compilation. (In the past we recovered and continued, but in practice that leads to + // confusing subsequent error messages about cycles that then abort.) cycle_delay_bug - // we don't want recursive representability calls to be forced with + // We don't want recursive representability calls to be forced with // incremental compilation because, if a cycle occurs, we need the - // entire cycle to be in memory for diagnostics + // entire cycle to be in memory for diagnostics. This means we can't + // use `ensure_ok()` with this query. anon } - /// An implementation detail for the `representability` query - query representability_adt_ty(key: Ty<'tcx>) -> rustc_middle::ty::Representability { + /// An implementation detail for the `check_representability` query. See that query for more + /// details, particularly on the modifiers. + query check_representability_adt_ty(key: Ty<'tcx>) -> rustc_middle::ty::Representability { desc { "checking if `{}` is representable", key } cycle_delay_bug anon diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index c141eb0311dc..6a51ea4deffe 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -741,8 +741,7 @@ pub fn sizedness_constraint( } } +/// This type exists just so a `FromCycleError` impl can be made for the `check_representability` +/// query. #[derive(Clone, Copy, Debug, HashStable)] -pub enum Representability { - Representable, - Infinite(ErrorGuaranteed), -} +pub struct Representability; diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 5c4c1733be29..b454689e243d 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -61,10 +61,9 @@ pub(crate) fn provide(providers: &mut Providers) { /// requires calling [`InhabitedPredicate::instantiate`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) { - return InhabitedPredicate::True; - } + let _ = tcx.check_representability(def_id); } + let adt = tcx.adt_def(def_id); InhabitedPredicate::any( tcx, diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index 328bd4a02c8f..eb6942ba491f 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -95,7 +95,7 @@ fn from_cycle_error( let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::representability + if info.frame.dep_kind == DepKind::check_representability && let Some(field_id) = info.frame.def_id && let Some(field_id) = field_id.as_local() && let Some(DefKind::Field) = info.frame.info.def_kind @@ -109,7 +109,7 @@ fn from_cycle_error( } } for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::representability_adt_ty + if info.frame.dep_kind == DepKind::check_representability_adt_ty && let Some(def_id) = info.frame.def_id_for_ty_in_cycle && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 33d334092ba9..1814e7604a2d 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -6,69 +6,71 @@ use rustc_span::def_id::LocalDefId; pub(crate) fn provide(providers: &mut Providers) { - *providers = - Providers { representability, representability_adt_ty, params_in_repr, ..*providers }; -} - -macro_rules! rtry { - ($e:expr) => { - match $e { - e @ Representability::Infinite(_) => return e, - Representability::Representable => {} - } + *providers = Providers { + check_representability, + check_representability_adt_ty, + params_in_repr, + ..*providers }; } -fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { +fn check_representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { match tcx.def_kind(def_id) { DefKind::Struct | DefKind::Union | DefKind::Enum => { for variant in tcx.adt_def(def_id).variants() { for field in variant.fields.iter() { - rtry!(tcx.representability(field.did.expect_local())); + let _ = tcx.check_representability(field.did.expect_local()); } } - Representability::Representable } - DefKind::Field => representability_ty(tcx, tcx.type_of(def_id).instantiate_identity()), + DefKind::Field => { + check_representability_ty(tcx, tcx.type_of(def_id).instantiate_identity()); + } def_kind => bug!("unexpected {def_kind:?}"), } + Representability } -fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { +fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { match *ty.kind() { - ty::Adt(..) => tcx.representability_adt_ty(ty), + // This one must be a query rather than a vanilla `check_representability_adt_ty` call. See + // the comment on `check_representability_adt_ty` below for why. + ty::Adt(..) => { + let _ = tcx.check_representability_adt_ty(ty); + } // FIXME(#11924) allow zero-length arrays? - ty::Array(ty, _) => representability_ty(tcx, ty), + ty::Array(ty, _) => { + check_representability_ty(tcx, ty); + } ty::Tuple(tys) => { for ty in tys { - rtry!(representability_ty(tcx, ty)); + check_representability_ty(tcx, ty); } - Representability::Representable } - _ => Representability::Representable, + _ => {} } } -/* -The reason for this being a separate query is very subtle: -Consider this infinitely sized struct: `struct Foo(Box, Bar)`: -When calling representability(Foo), a query cycle will occur: - representability(Foo) - -> representability_adt_ty(Bar) - -> representability(Foo) -For the diagnostic output (in `Value::from_cycle_error`), we want to detect that -the `Foo` in the *second* field of the struct is culpable. This requires -traversing the HIR of the struct and calling `params_in_repr(Bar)`. But we can't -call params_in_repr for a given type unless it is known to be representable. -params_in_repr will cycle/panic on infinitely sized types. Looking at the query -cycle above, we know that `Bar` is representable because -representability_adt_ty(Bar<..>) is in the cycle and representability(Bar) is -*not* in the cycle. -*/ -fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { +// The reason for this being a separate query is very subtle. Consider this +// infinitely sized struct: `struct Foo(Box, Bar)`. When calling +// check_representability(Foo), a query cycle will occur: +// +// check_representability(Foo) +// -> check_representability_adt_ty(Bar) +// -> check_representability(Foo) +// +// For the diagnostic output (in `Value::from_cycle_error`), we want to detect +// that the `Foo` in the *second* field of the struct is culpable. This +// requires traversing the HIR of the struct and calling `params_in_repr(Bar)`. +// But we can't call params_in_repr for a given type unless it is known to be +// representable. params_in_repr will cycle/panic on infinitely sized types. +// Looking at the query cycle above, we know that `Bar` is representable +// because `check_representability_adt_ty(Bar<..>)` is in the cycle and +// `check_representability(Bar)` is *not* in the cycle. +fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") }; if let Some(def_id) = adt.did().as_local() { - rtry!(tcx.representability(def_id)); + let _ = tcx.check_representability(def_id); } // At this point, we know that the item of the ADT type is representable; // but the type parameters may cause a cycle with an upstream type @@ -76,11 +78,11 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab for (i, arg) in args.iter().enumerate() { if let ty::GenericArgKind::Type(ty) = arg.kind() { if params_in_repr.contains(i as u32) { - rtry!(representability_ty(tcx, ty)); + check_representability_ty(tcx, ty); } } } - Representability::Representable + Representability } fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DenseBitSet { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index d6a29aba22b9..78f3a1922887 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -116,11 +116,10 @@ fn adt_sizedness_constraint<'tcx>( tcx: TyCtxt<'tcx>, (def_id, sizedness): (DefId, SizedTraitKind), ) -> Option>> { - if let Some(def_id) = def_id.as_local() - && let ty::Representability::Infinite(_) = tcx.representability(def_id) - { - return None; + if let Some(def_id) = def_id.as_local() { + let _ = tcx.check_representability(def_id); } + let def = tcx.adt_def(def_id); if !def.is_struct() { From cbd443d7293805720b82be0c7e85da527d52c193 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 12 Feb 2026 11:35:58 +0800 Subject: [PATCH 43/59] Remove unused features in tools --- src/tools/miri/src/lib.rs | 2 ++ src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs | 2 +- src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs | 3 ++- src/tools/test-float-parse/src/lib.rs | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 32cadddc33aa..e5791d333fd7 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -41,6 +41,8 @@ clippy::len_zero, // We are not implementing queries here so it's fine rustc::potential_query_instability, + // FIXME: Unused features should be removed in the future + unused_features, )] #![warn( rust_2018_idioms, diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 68b3afc3e841..e83ddb859498 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -10,7 +10,7 @@ feature = "sysroot-abi", feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span) )] -#![allow(internal_features)] +#![allow(internal_features, unused_features)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 65de80440483..734cb4ecc169 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -18,7 +18,8 @@ internal_features, clippy::disallowed_types, clippy::print_stderr, - unused_crate_dependencies + unused_crate_dependencies, + unused_features )] #![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)] diff --git a/src/tools/test-float-parse/src/lib.rs b/src/tools/test-float-parse/src/lib.rs index 1321a3c33549..da83aeea3c13 100644 --- a/src/tools/test-float-parse/src/lib.rs +++ b/src/tools/test-float-parse/src/lib.rs @@ -1,5 +1,5 @@ -#![feature(f16)] #![feature(cfg_target_has_reliable_f16_f128)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] #![expect(internal_features)] // reliable_f16_f128 mod traits; From 7ffaa416620a9032c7a8fc9e5837822b849553a3 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Fri, 20 Feb 2026 14:34:01 +0800 Subject: [PATCH 44/59] Remove unused features in library tests --- library/alloctests/tests/lib.rs | 1 - library/core/src/num/f16.rs | 6 +++++- library/core/src/num/f32.rs | 1 + library/core/src/num/f64.rs | 1 + library/coretests/tests/lib.rs | 1 - library/std/src/num/f16.rs | 1 + library/std/src/process.rs | 2 ++ 7 files changed, 10 insertions(+), 3 deletions(-) diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 60b26126cf6b..699a5010282b 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -1,6 +1,5 @@ #![feature(allocator_api)] #![feature(binary_heap_pop_if)] -#![feature(btree_merge)] #![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index ef937fccb47f..ff483f4062ac 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1521,7 +1521,11 @@ pub const fn algebraic_rem(self, rhs: f16) -> f16 { // Functions in this module fall into `core_float_math` // #[unstable(feature = "core_float_math", issue = "137578")] #[cfg(not(test))] -#[doc(test(attr(feature(cfg_target_has_reliable_f16_f128), expect(internal_features))))] +#[doc(test(attr( + feature(cfg_target_has_reliable_f16_f128), + expect(internal_features), + allow(unused_features) +)))] impl f16 { /// Returns the largest integer less than or equal to `self`. /// diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index aac81d48c1b4..63abb5adcbfb 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -393,6 +393,7 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } +#[doc(test(attr(allow(unused_features))))] impl f32 { /// The radix or base of the internal representation of `f32`. #[stable(feature = "assoc_int_consts", since = "1.43.0")] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index bacf429e77fa..1294e094e4a0 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -393,6 +393,7 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } +#[doc(test(attr(allow(unused_features))))] impl f64 { /// The radix or base of the internal representation of `f64`. #[stable(feature = "assoc_int_consts", since = "1.43.0")] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 7cd946dc9a03..d150d2f622d9 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -51,7 +51,6 @@ #![feature(f16)] #![feature(f128)] #![feature(float_algebraic)] -#![feature(float_bits_const)] #![feature(float_exact_integer_constants)] #![feature(float_gamma)] #![feature(float_minimum_maximum)] diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs index 318a0b3af86a..7ca266c8a5f6 100644 --- a/library/std/src/num/f16.rs +++ b/library/std/src/num/f16.rs @@ -16,6 +16,7 @@ use crate::sys::cmath; #[cfg(not(test))] +#[doc(test(attr(allow(unused_features))))] impl f16 { /// Raises a number to a floating point power. /// diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 1199403b1d5a..4b3bfa5335bf 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1380,6 +1380,7 @@ impl Output { /// # Examples /// /// ``` + /// # #![allow(unused_features)] /// #![feature(exit_status_error)] /// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] { /// use std::process::Command; @@ -1959,6 +1960,7 @@ impl crate::sealed::Sealed for ExitStatusError {} pub struct ExitStatusError(imp::ExitStatusError); #[unstable(feature = "exit_status_error", issue = "84908")] +#[doc(test(attr(allow(unused_features))))] impl ExitStatusError { /// Reports the exit code, if applicable, from an `ExitStatusError`. /// From 0436634084b41b7af7d0a11459fad14a0b53ef59 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sat, 28 Feb 2026 21:38:09 +0800 Subject: [PATCH 45/59] Remove unused features in tests --- .../add_private_fn_at_krate_root_cc/struct_point.rs | 1 - tests/incremental/change_add_field/struct_point.rs | 1 - tests/incremental/change_crate_dep_kind.rs | 2 +- tests/incremental/change_private_fn/struct_point.rs | 1 - tests/incremental/change_private_fn_cc/struct_point.rs | 1 - .../incremental/change_private_impl_method/struct_point.rs | 1 - .../change_private_impl_method_cc/struct_point.rs | 1 - .../change_pub_inherent_method_body/struct_point.rs | 1 - .../change_pub_inherent_method_sig/struct_point.rs | 1 - tests/ui-fulldeps/rustc_public/check_abi.rs | 1 - tests/ui-fulldeps/rustc_public/check_transform.rs | 1 - tests/ui/allocator/xcrate-use2.rs | 1 - tests/ui/associated-types/associated-types-impl-redirect.rs | 1 - .../associated-types-where-clause-impl-ambiguity.rs | 1 - tests/ui/async-await/async-drop/async-drop-initial.rs | 2 +- tests/ui/backtrace/line-tables-only.rs | 1 - tests/ui/borrowck/super-let-lifetime-and-drop.rs | 2 +- tests/ui/cfg/cfg_stmt_expr.rs | 1 - tests/ui/const-generics/transmute.rs | 1 - tests/ui/consts/const-fn-type-name.rs | 1 - tests/ui/consts/const-ptr-nonnull-rpass.rs | 2 +- tests/ui/consts/try-operator.rs | 1 - tests/ui/contracts/internal_machinery/lowering/basics.rs | 2 +- tests/ui/coroutine/control-flow.rs | 2 +- tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed | 2 +- tests/ui/coroutine/missing_coroutine_attr_suggestion.rs | 2 +- tests/ui/coroutine/non-static-is-unpin.rs | 2 +- tests/ui/coroutine/other-attribute-on-gen.rs | 1 - tests/ui/coroutine/pin-box-coroutine.rs | 2 +- tests/ui/coroutine/xcrate.rs | 2 +- tests/ui/eii/default/call_default.rs | 1 - tests/ui/eii/default/call_default_panics.rs | 1 - tests/ui/eii/default/call_impl.rs | 1 - tests/ui/eii/linking/codegen_cross_crate.rs | 1 - tests/ui/eii/privacy1.rs | 1 - tests/ui/extern/extern-prelude-core.rs | 1 - .../feature-gate-explicit-extern-abis.current.fixed | 1 - .../feature-gate-explicit-extern-abis.current.stderr | 6 +++--- .../feature-gate-explicit-extern-abis.current_feature.fixed | 1 - ...feature-gate-explicit-extern-abis.current_feature.stderr | 6 +++--- .../feature-gate-explicit-extern-abis.future.fixed | 1 - .../feature-gate-explicit-extern-abis.future.stderr | 6 +++--- .../feature-gate-explicit-extern-abis.future_feature.stderr | 6 +++--- tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs | 1 - tests/ui/float/classify-runtime-const.rs | 2 -- tests/ui/float/conv-bits-runtime-const.rs | 5 +++-- tests/ui/fmt/format-macro-no-std.rs | 1 - .../half-open-range-pats-semantics.rs | 4 ++-- tests/ui/hygiene/xcrate.rs | 1 - tests/ui/impl-trait/example-calendar.rs | 3 +-- tests/ui/intrinsics/intrinsic-alignment.rs | 2 +- tests/ui/io-checks/write-macro-error.rs | 1 - tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs | 2 +- tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs | 1 - tests/ui/lint/lint-unknown-feature.rs | 1 - .../lint-unnecessary-qualification-issue-121331.fixed | 2 +- .../lint-unnecessary-qualification-issue-121331.rs | 2 +- tests/ui/lint/unused/unused_attributes-must_use.fixed | 2 +- tests/ui/lint/unused/unused_attributes-must_use.rs | 2 +- tests/ui/lowering/issue-96847.rs | 1 - tests/ui/lowering/issue-96847.stderr | 2 +- tests/ui/macros/metavar_cross_edition_recursive_macros.rs | 1 - .../macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs | 2 +- .../all-not-available-cases.rs | 2 +- ...t-with-custom-errors-does-not-create-unnecessary-code.rs | 1 - ...ert-without-captures-does-not-create-unnecessary-code.rs | 2 +- .../feature-gate-generic_assert.rs | 2 +- tests/ui/macros/stringify.rs | 2 -- tests/ui/match/match-float.rs | 4 ++-- tests/ui/methods/supertrait-shadowing/out-of-scope.rs | 1 - tests/ui/nll/issue-48623-coroutine.rs | 2 +- tests/ui/overloaded/overloaded-calls-simple.rs | 2 +- tests/ui/sanitizer/memory-passing.rs | 1 - tests/ui/simd/monomorphize-shuffle-index.rs | 2 +- tests/ui/structs-enums/rec-align-u32.rs | 2 +- tests/ui/structs-enums/rec-align-u64.rs | 2 +- .../auxiliary/thread-local-extern-static.rs | 3 ++- tests/ui/threads-sendsync/thread-local-extern-static.rs | 3 ++- tests/ui/traits/alias/import-cross-crate.rs | 1 - tests/ui/traits/overlap-permitted-for-marker-traits.rs | 1 - tests/ui/type/typeid-consistency.rs | 1 - tests/ui/typeck/type-name-intrinsic-usage-61894.rs | 1 - 82 files changed, 51 insertions(+), 96 deletions(-) diff --git a/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs index 0367af8d53b8..be1f27e7bae3 100644 --- a/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs +++ b/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -9,7 +9,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_add_field/struct_point.rs b/tests/incremental/change_add_field/struct_point.rs index fb363c9ce496..024812bd4beb 100644 --- a/tests/incremental/change_add_field/struct_point.rs +++ b/tests/incremental/change_add_field/struct_point.rs @@ -9,7 +9,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_crate_dep_kind.rs b/tests/incremental/change_crate_dep_kind.rs index 4fd0c345aad2..d08e76c47527 100644 --- a/tests/incremental/change_crate_dep_kind.rs +++ b/tests/incremental/change_crate_dep_kind.rs @@ -8,7 +8,7 @@ //@ build-pass (FIXME(62277): could be check-pass?) //@ ignore-backends: gcc -#![feature(panic_unwind)] +#![cfg_attr(cfail1, feature(panic_unwind))] // Turn the panic_unwind crate from an explicit into an implicit query: #[cfg(cfail1)] diff --git a/tests/incremental/change_private_fn/struct_point.rs b/tests/incremental/change_private_fn/struct_point.rs index cce26fa7a3e6..2c2560309d27 100644 --- a/tests/incremental/change_private_fn/struct_point.rs +++ b/tests/incremental/change_private_fn/struct_point.rs @@ -7,7 +7,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_private_fn_cc/struct_point.rs b/tests/incremental/change_private_fn_cc/struct_point.rs index 87392ca857ed..cfe26be225d3 100644 --- a/tests/incremental/change_private_fn_cc/struct_point.rs +++ b/tests/incremental/change_private_fn_cc/struct_point.rs @@ -9,7 +9,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] diff --git a/tests/incremental/change_private_impl_method/struct_point.rs b/tests/incremental/change_private_impl_method/struct_point.rs index dc0ba82c0a31..42793b53378d 100644 --- a/tests/incremental/change_private_impl_method/struct_point.rs +++ b/tests/incremental/change_private_impl_method/struct_point.rs @@ -7,7 +7,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_private_impl_method_cc/struct_point.rs b/tests/incremental/change_private_impl_method_cc/struct_point.rs index eb51af720949..c554a2f3db96 100644 --- a/tests/incremental/change_private_impl_method_cc/struct_point.rs +++ b/tests/incremental/change_private_impl_method_cc/struct_point.rs @@ -9,7 +9,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] diff --git a/tests/incremental/change_pub_inherent_method_body/struct_point.rs b/tests/incremental/change_pub_inherent_method_body/struct_point.rs index b8e06d070a3c..d02443226669 100644 --- a/tests/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/tests/incremental/change_pub_inherent_method_body/struct_point.rs @@ -7,7 +7,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![rustc_partition_codegened(module="struct_point-point", cfg="cfail2")] diff --git a/tests/incremental/change_pub_inherent_method_sig/struct_point.rs b/tests/incremental/change_pub_inherent_method_sig/struct_point.rs index 3672ec268010..5c24199df6aa 100644 --- a/tests/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/tests/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -7,7 +7,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] // These are expected to require codegen. diff --git a/tests/ui-fulldeps/rustc_public/check_abi.rs b/tests/ui-fulldeps/rustc_public/check_abi.rs index 8e97b773db56..d823e76b93cd 100644 --- a/tests/ui-fulldeps/rustc_public/check_abi.rs +++ b/tests/ui-fulldeps/rustc_public/check_abi.rs @@ -6,7 +6,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(ascii_char, ascii_char_variants)] extern crate rustc_driver; extern crate rustc_hir; diff --git a/tests/ui-fulldeps/rustc_public/check_transform.rs b/tests/ui-fulldeps/rustc_public/check_transform.rs index f8aa40e47446..000f1f4cb365 100644 --- a/tests/ui-fulldeps/rustc_public/check_transform.rs +++ b/tests/ui-fulldeps/rustc_public/check_transform.rs @@ -6,7 +6,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; extern crate rustc_middle; diff --git a/tests/ui/allocator/xcrate-use2.rs b/tests/ui/allocator/xcrate-use2.rs index a48b0beeb07e..4580d0f908bb 100644 --- a/tests/ui/allocator/xcrate-use2.rs +++ b/tests/ui/allocator/xcrate-use2.rs @@ -5,7 +5,6 @@ //@ aux-build:helper.rs //@ no-prefer-dynamic -#![feature(allocator_api)] extern crate custom; extern crate custom_as_global; diff --git a/tests/ui/associated-types/associated-types-impl-redirect.rs b/tests/ui/associated-types/associated-types-impl-redirect.rs index 64cae31e5693..11812c7212bb 100644 --- a/tests/ui/associated-types/associated-types-impl-redirect.rs +++ b/tests/ui/associated-types/associated-types-impl-redirect.rs @@ -9,7 +9,6 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs b/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs index 0de7617943c6..fd4043870442 100644 --- a/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs +++ b/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs @@ -8,7 +8,6 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/tests/ui/async-await/async-drop/async-drop-initial.rs b/tests/ui/async-await/async-drop/async-drop-initial.rs index cd33c143fba0..427ed54fa6ca 100644 --- a/tests/ui/async-await/async-drop/async-drop-initial.rs +++ b/tests/ui/async-await/async-drop/async-drop-initial.rs @@ -5,7 +5,7 @@ // please consider modifying miri's async drop test at // `src/tools/miri/tests/pass/async-drop.rs`. -#![feature(async_drop, impl_trait_in_assoc_type)] +#![feature(async_drop)] #![allow(incomplete_features, dead_code)] //@ edition: 2021 diff --git a/tests/ui/backtrace/line-tables-only.rs b/tests/ui/backtrace/line-tables-only.rs index 7dac41119a32..b3ae8a1971b9 100644 --- a/tests/ui/backtrace/line-tables-only.rs +++ b/tests/ui/backtrace/line-tables-only.rs @@ -18,7 +18,6 @@ //@ needs-unwind //@ aux-build: line-tables-only-helper.rs -#![feature(backtrace_frames)] extern crate line_tables_only_helper; diff --git a/tests/ui/borrowck/super-let-lifetime-and-drop.rs b/tests/ui/borrowck/super-let-lifetime-and-drop.rs index 380470f792fe..a103a6a804cc 100644 --- a/tests/ui/borrowck/super-let-lifetime-and-drop.rs +++ b/tests/ui/borrowck/super-let-lifetime-and-drop.rs @@ -7,7 +7,7 @@ //@ [borrowck] check-fail #![allow(dropping_references)] -#![feature(super_let, stmt_expr_attributes)] +#![feature(super_let)] use std::convert::identity; diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs index 361b159a354f..128321a23320 100644 --- a/tests/ui/cfg/cfg_stmt_expr.rs +++ b/tests/ui/cfg/cfg_stmt_expr.rs @@ -3,7 +3,6 @@ #![allow(unused_mut)] #![allow(unused_variables)] #![deny(non_snake_case)] -#![feature(stmt_expr_attributes)] fn main() { let a = 413; diff --git a/tests/ui/const-generics/transmute.rs b/tests/ui/const-generics/transmute.rs index e8ab8637932d..6108139f3ce5 100644 --- a/tests/ui/const-generics/transmute.rs +++ b/tests/ui/const-generics/transmute.rs @@ -1,6 +1,5 @@ //@ run-pass #![feature(generic_const_exprs)] -#![feature(transmute_generic_consts)] #![allow(incomplete_features)] fn ident(v: [[u32; H]; W]) -> [[u32; H]; W] { diff --git a/tests/ui/consts/const-fn-type-name.rs b/tests/ui/consts/const-fn-type-name.rs index 733ab79b7cdb..5da86de8f67c 100644 --- a/tests/ui/consts/const-fn-type-name.rs +++ b/tests/ui/consts/const-fn-type-name.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] -#![feature(const_type_name)] #![allow(dead_code)] const fn type_name_wrapper(_: &T) -> &'static str { diff --git a/tests/ui/consts/const-ptr-nonnull-rpass.rs b/tests/ui/consts/const-ptr-nonnull-rpass.rs index 48ad72df6309..ebea036c1647 100644 --- a/tests/ui/consts/const-ptr-nonnull-rpass.rs +++ b/tests/ui/consts/const-ptr-nonnull-rpass.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(ptr_internals, test)] +#![feature(test)] extern crate test; use test::black_box as b; // prevent promotion of the argument and const-propagation of the result diff --git a/tests/ui/consts/try-operator.rs b/tests/ui/consts/try-operator.rs index cd0bf8ea5716..54a6ed26241c 100644 --- a/tests/ui/consts/try-operator.rs +++ b/tests/ui/consts/try-operator.rs @@ -1,7 +1,6 @@ //@ ignore-backends: gcc //@ run-pass -#![feature(try_trait_v2)] #![feature(const_trait_impl)] #![feature(const_try)] diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.rs b/tests/ui/contracts/internal_machinery/lowering/basics.rs index 7b3a769af825..f4f5dc5ab105 100644 --- a/tests/ui/contracts/internal_machinery/lowering/basics.rs +++ b/tests/ui/contracts/internal_machinery/lowering/basics.rs @@ -1,6 +1,6 @@ //@ run-pass #![expect(incomplete_features)] -#![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)] +#![feature(contracts, contracts_internals, core_intrinsics)] extern crate core; diff --git a/tests/ui/coroutine/control-flow.rs b/tests/ui/coroutine/control-flow.rs index f64b6f738836..fe611b1c1c31 100644 --- a/tests/ui/coroutine/control-flow.rs +++ b/tests/ui/coroutine/control-flow.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] +#![feature(coroutines, coroutine_trait)] use std::ops::{CoroutineState, Coroutine}; use std::pin::Pin; diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed index 128f09a11843..9bda140ce58c 100644 --- a/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed @@ -1,6 +1,6 @@ //@ run-rustfix -#![feature(coroutines, gen_blocks, stmt_expr_attributes)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { let _ = #[coroutine] || yield; diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs index dc9525914960..d8af486e6d05 100644 --- a/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs @@ -1,6 +1,6 @@ //@ run-rustfix -#![feature(coroutines, gen_blocks, stmt_expr_attributes)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { let _ = || yield; diff --git a/tests/ui/coroutine/non-static-is-unpin.rs b/tests/ui/coroutine/non-static-is-unpin.rs index b28bf1977145..7dc036077f90 100644 --- a/tests/ui/coroutine/non-static-is-unpin.rs +++ b/tests/ui/coroutine/non-static-is-unpin.rs @@ -3,7 +3,7 @@ //@[next] compile-flags: -Znext-solver //@ run-pass -#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] +#![feature(coroutines)] #![allow(dropping_copy_types)] use std::marker::PhantomPinned; diff --git a/tests/ui/coroutine/other-attribute-on-gen.rs b/tests/ui/coroutine/other-attribute-on-gen.rs index 5f4584ee0226..e13a0abcbfd6 100644 --- a/tests/ui/coroutine/other-attribute-on-gen.rs +++ b/tests/ui/coroutine/other-attribute-on-gen.rs @@ -2,7 +2,6 @@ //@ run-pass #![feature(gen_blocks)] #![feature(optimize_attribute)] -#![feature(stmt_expr_attributes)] #![feature(async_iterator)] #![allow(dead_code)] diff --git a/tests/ui/coroutine/pin-box-coroutine.rs b/tests/ui/coroutine/pin-box-coroutine.rs index d030f3ef214d..d9674ed7341b 100644 --- a/tests/ui/coroutine/pin-box-coroutine.rs +++ b/tests/ui/coroutine/pin-box-coroutine.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] +#![feature(coroutines, coroutine_trait)] use std::ops::Coroutine; diff --git a/tests/ui/coroutine/xcrate.rs b/tests/ui/coroutine/xcrate.rs index 406152a0bf10..6b4d81fc983f 100644 --- a/tests/ui/coroutine/xcrate.rs +++ b/tests/ui/coroutine/xcrate.rs @@ -2,7 +2,7 @@ //@ aux-build:xcrate.rs -#![feature(coroutines, coroutine_trait)] +#![feature(coroutine_trait)] extern crate xcrate; diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index c13df48e9921..b60a1dd0b215 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -7,7 +7,6 @@ //@ ignore-windows // Tests EIIs with default implementations. // When there's no explicit declaration, the default should be called from the declaring crate. -#![feature(extern_item_impls)] extern crate decl_with_default; diff --git a/tests/ui/eii/default/call_default_panics.rs b/tests/ui/eii/default/call_default_panics.rs index f71fddb71ba2..96b2742aa8e0 100644 --- a/tests/ui/eii/default/call_default_panics.rs +++ b/tests/ui/eii/default/call_default_panics.rs @@ -23,7 +23,6 @@ // ``` // This is a simple test to make sure that we can unwind through these, // and that this wrapper function effectively doesn't show up in the trace. -#![feature(extern_item_impls)] extern crate decl_with_default_panics; diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index 94b2aa552a1e..b88769757489 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -9,7 +9,6 @@ // Tests EIIs with default implementations. // When an explicit implementation is given in one dependency, and the declaration is in another, // the explicit implementation is preferred. -#![feature(extern_item_impls)] extern crate decl_with_default; extern crate impl1; diff --git a/tests/ui/eii/linking/codegen_cross_crate.rs b/tests/ui/eii/linking/codegen_cross_crate.rs index 4016712e7504..2958a0f10521 100644 --- a/tests/ui/eii/linking/codegen_cross_crate.rs +++ b/tests/ui/eii/linking/codegen_cross_crate.rs @@ -6,7 +6,6 @@ // FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether calling EIIs works with the declaration in another crate. -#![feature(extern_item_impls)] extern crate codegen_cross_crate_other_crate as codegen; diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index 72aec83d2cee..60bf36074e0a 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -5,7 +5,6 @@ // FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether re-exports work. -#![feature(extern_item_impls)] extern crate other_crate_privacy1 as codegen; diff --git a/tests/ui/extern/extern-prelude-core.rs b/tests/ui/extern/extern-prelude-core.rs index 5108c02517c3..05d3750ae656 100644 --- a/tests/ui/extern/extern-prelude-core.rs +++ b/tests/ui/extern/extern-prelude-core.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(lang_items)] #![no_std] extern crate std as other; diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed index 525f78d162fc..a2b920880221 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern "C" fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr index cf927807c7c3..f5cc09bef5e5 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr @@ -1,5 +1,5 @@ warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` @@ -7,13 +7,13 @@ LL | extern fn _foo() {} = note: `#[warn(missing_abi)]` on by default warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed index 525f78d162fc..a2b920880221 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern "C" fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr index cf927807c7c3..f5cc09bef5e5 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr @@ -1,5 +1,5 @@ warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` @@ -7,13 +7,13 @@ LL | extern fn _foo() {} = note: `#[warn(missing_abi)]` on by default warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed index 525f78d162fc..a2b920880221 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern "C" fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr index cf927807c7c3..f5cc09bef5e5 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr @@ -1,5 +1,5 @@ warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` @@ -7,13 +7,13 @@ LL | extern fn _foo() {} = note: `#[warn(missing_abi)]` on by default warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr index 096a6f434169..3fad1cc76dd7 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr @@ -1,5 +1,5 @@ error: `extern` declarations without an explicit ABI are disallowed - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: specify an ABI: `extern ""` @@ -7,7 +7,7 @@ LL | extern fn _foo() {} = help: prior to Rust 2024, a default ABI was inferred error: `extern` declarations without an explicit ABI are disallowed - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: specify an ABI: `extern ""` @@ -15,7 +15,7 @@ LL | unsafe extern fn _bar() {} = help: prior to Rust 2024, a default ABI was inferred error: `extern` declarations without an explicit ABI are disallowed - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: specify an ABI: `extern ""` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs index 379c45f58990..2ddc817768a1 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs index ca852ea2468b..fb7361f9cbad 100644 --- a/tests/ui/float/classify-runtime-const.rs +++ b/tests/ui/float/classify-runtime-const.rs @@ -6,8 +6,6 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(f16)] -#![feature(f128)] use std::num::FpCategory::*; diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs index 1373001b74da..e7b306714bb8 100644 --- a/tests/ui/float/conv-bits-runtime-const.rs +++ b/tests/ui/float/conv-bits-runtime-const.rs @@ -3,9 +3,10 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(f16)] -#![feature(f128)] #![feature(cfg_target_has_reliable_f16_f128)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] +#![cfg_attr(target_has_reliable_f128, feature(f128))] + #![allow(unused_macro_rules)] // expect the unexpected (`target_has_reliable_*` are not "known" configs since they are unstable) #![expect(unexpected_cfgs)] diff --git a/tests/ui/fmt/format-macro-no-std.rs b/tests/ui/fmt/format-macro-no-std.rs index d096b4de0139..31c3a9a95066 100644 --- a/tests/ui/fmt/format-macro-no-std.rs +++ b/tests/ui/fmt/format-macro-no-std.rs @@ -4,7 +4,6 @@ //@ ignore-emscripten no no_std executables //@ ignore-wasm different `main` convention -#![feature(lang_items)] #![no_std] #![no_main] diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs index df1b9e164c76..2f25f0078eec 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs @@ -6,8 +6,8 @@ #![allow(unreachable_patterns)] #![feature(cfg_target_has_reliable_f16_f128)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] +#![cfg_attr(target_has_reliable_f128, feature(f128))] macro_rules! yes { ($scrutinee:expr, $($t:tt)+) => { diff --git a/tests/ui/hygiene/xcrate.rs b/tests/ui/hygiene/xcrate.rs index 0dd9136e4d56..aa221cb5ad2a 100644 --- a/tests/ui/hygiene/xcrate.rs +++ b/tests/ui/hygiene/xcrate.rs @@ -3,7 +3,6 @@ //@ aux-build:xcrate.rs -#![feature(decl_macro)] extern crate xcrate; diff --git a/tests/ui/impl-trait/example-calendar.rs b/tests/ui/impl-trait/example-calendar.rs index c3c01f010366..972ee5f4b63b 100644 --- a/tests/ui/impl-trait/example-calendar.rs +++ b/tests/ui/impl-trait/example-calendar.rs @@ -1,7 +1,6 @@ //@ run-pass -#![feature(fn_traits, - step_trait, +#![feature(step_trait, unboxed_closures, )] diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index 5fee6b0b3978..242eea1f8407 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(core_intrinsics, rustc_attrs)] +#![feature(rustc_attrs)] #[cfg(any( target_os = "aix", diff --git a/tests/ui/io-checks/write-macro-error.rs b/tests/ui/io-checks/write-macro-error.rs index 857ea0024e16..90b9537b56da 100644 --- a/tests/ui/io-checks/write-macro-error.rs +++ b/tests/ui/io-checks/write-macro-error.rs @@ -4,7 +4,6 @@ //@ run-pass //@ needs-unwind -#![feature(io_error_uncategorized)] use std::fmt; use std::io::{self, Error, Write}; diff --git a/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs b/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs index 48ca39300f41..6f66e6c0f67f 100644 --- a/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs +++ b/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs @@ -15,7 +15,7 @@ #![allow(incomplete_features)] #![feature(raw_dylib_elf)] -#![feature(native_link_modifiers_as_needed)] +#![cfg_attr(not(no_modifier), feature(native_link_modifiers_as_needed))] #[cfg_attr( as_needed, diff --git a/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs b/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs index eb110869e44e..77ef6fab16cd 100644 --- a/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs +++ b/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(stmt_expr_attributes)] #![deny(unused_parens)] // Tests that lint attributes on statements/expressions are diff --git a/tests/ui/lint/lint-unknown-feature.rs b/tests/ui/lint/lint-unknown-feature.rs index 188617467974..b598f0d0106b 100644 --- a/tests/ui/lint/lint-unknown-feature.rs +++ b/tests/ui/lint/lint-unknown-feature.rs @@ -4,6 +4,5 @@ #![allow(stable_features)] // FIXME(#44232) we should warn that this isn't used. -#![feature(rust1)] fn main() {} diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed index d554bbfcc98c..a3d8b1d32a89 100644 --- a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed @@ -2,7 +2,7 @@ //@ edition:2021 #![deny(unused_qualifications)] #![deny(unused_imports)] -#![feature(coroutines, coroutine_trait)] +#![feature(coroutine_trait)] use std::ops::{ Coroutine, diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs index 4d79f5ab7453..2da45507e3e7 100644 --- a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs @@ -2,7 +2,7 @@ //@ edition:2021 #![deny(unused_qualifications)] #![deny(unused_imports)] -#![feature(coroutines, coroutine_trait)] +#![feature(coroutine_trait)] use std::ops::{ Coroutine, diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed index fa596da95ccd..082096f12080 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.fixed +++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed @@ -1,6 +1,6 @@ //@ run-rustfix -#![allow(dead_code, path_statements)] +#![allow(dead_code, path_statements, unused_features)] #![deny(unused_attributes, unused_must_use)] #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)] diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs index 3e72dd1e4383..b4b17476d0b1 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.rs +++ b/tests/ui/lint/unused/unused_attributes-must_use.rs @@ -1,6 +1,6 @@ //@ run-rustfix -#![allow(dead_code, path_statements)] +#![allow(dead_code, path_statements, unused_features)] #![deny(unused_attributes, unused_must_use)] #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)] diff --git a/tests/ui/lowering/issue-96847.rs b/tests/ui/lowering/issue-96847.rs index a1fd105d9dd4..6ee40338043f 100644 --- a/tests/ui/lowering/issue-96847.rs +++ b/tests/ui/lowering/issue-96847.rs @@ -3,7 +3,6 @@ // Test that this doesn't abort during AST lowering. In #96847 it did abort // because the attribute was being lowered twice. -#![feature(stmt_expr_attributes)] #![feature(lang_items)] fn main() { diff --git a/tests/ui/lowering/issue-96847.stderr b/tests/ui/lowering/issue-96847.stderr index 2cded32f9fb8..26bc6645ce6d 100644 --- a/tests/ui/lowering/issue-96847.stderr +++ b/tests/ui/lowering/issue-96847.stderr @@ -1,5 +1,5 @@ error[E0522]: definition of an unknown lang item: `foo` - --> $DIR/issue-96847.rs:11:9 + --> $DIR/issue-96847.rs:10:9 | LL | #![lang="foo"] | ^^^^^^^^^^^^^^ definition of unknown lang item `foo` diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs index ae1bc00236f0..4382c00ab13c 100644 --- a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs +++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs @@ -6,7 +6,6 @@ // This test captures the behavior of macro-generating-macros with fragment // specifiers across edition boundaries. -#![feature(macro_metavar_expr)] #![allow(incomplete_features)] extern crate metavar_2018; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs index de7dbb9052ed..b470cd622d03 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs @@ -5,7 +5,7 @@ //@ needs-unwind Asserting on contents of error message #![allow(path_statements, unused_allocation)] -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] macro_rules! test { ( diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs index 1600fd0af3f3..2165037244dc 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs @@ -4,7 +4,7 @@ //@ run-pass //@ needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs index 2a27164f9cba..d75eb8b0d761 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs @@ -3,7 +3,6 @@ //@ compile-flags: --test -Zpanic_abort_tests //@ run-pass -#![feature(core_intrinsics, generic_assert)] #[should_panic(expected = "Custom user message")] #[test] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs index 6e5f8d6cd12d..be4456604f62 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs @@ -3,7 +3,7 @@ //@ run-pass //@ needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs index 254d59076e53..a5ceb3d2ecd4 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs @@ -4,7 +4,7 @@ // ignore-tidy-linelength //@ run-pass -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] use std::fmt::{Debug, Formatter}; diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 890b429b4ac7..80c8d1cfe738 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -9,12 +9,10 @@ #![feature(const_trait_impl)] #![feature(coroutines)] #![feature(decl_macro)] -#![feature(explicit_tail_calls)] #![feature(more_qualified_paths)] #![feature(never_patterns)] #![feature(trait_alias)] #![feature(try_blocks)] -#![feature(type_ascription)] #![feature(yeet_expr)] #![deny(unused_macros)] diff --git a/tests/ui/match/match-float.rs b/tests/ui/match/match-float.rs index 279bb5927ac4..504740add537 100644 --- a/tests/ui/match/match-float.rs +++ b/tests/ui/match/match-float.rs @@ -3,8 +3,8 @@ // Makes sure we use `==` (not bitwise) semantics for float comparison. #![feature(cfg_target_has_reliable_f16_f128)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] +#![cfg_attr(target_has_reliable_f128, feature(f128))] #[cfg(target_has_reliable_f16)] fn check_f16() { diff --git a/tests/ui/methods/supertrait-shadowing/out-of-scope.rs b/tests/ui/methods/supertrait-shadowing/out-of-scope.rs index bd263be59cc7..8e0f5ba978e3 100644 --- a/tests/ui/methods/supertrait-shadowing/out-of-scope.rs +++ b/tests/ui/methods/supertrait-shadowing/out-of-scope.rs @@ -1,7 +1,6 @@ //@ run-pass //@ check-run-results -#![feature(supertrait_item_shadowing)] #![allow(dead_code)] mod out_of_scope { diff --git a/tests/ui/nll/issue-48623-coroutine.rs b/tests/ui/nll/issue-48623-coroutine.rs index 63348a2047c0..57f579106b7a 100644 --- a/tests/ui/nll/issue-48623-coroutine.rs +++ b/tests/ui/nll/issue-48623-coroutine.rs @@ -2,7 +2,7 @@ #![allow(path_statements)] #![allow(dead_code)] -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines)] struct WithDrop; diff --git a/tests/ui/overloaded/overloaded-calls-simple.rs b/tests/ui/overloaded/overloaded-calls-simple.rs index 34b674357d89..b53686aa9464 100644 --- a/tests/ui/overloaded/overloaded-calls-simple.rs +++ b/tests/ui/overloaded/overloaded-calls-simple.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(lang_items, unboxed_closures, fn_traits)] +#![feature(unboxed_closures, fn_traits)] struct S1 { x: i32, diff --git a/tests/ui/sanitizer/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs index 6ac41b178fe7..d41f62b310b0 100644 --- a/tests/ui/sanitizer/memory-passing.rs +++ b/tests/ui/sanitizer/memory-passing.rs @@ -13,7 +13,6 @@ // This test case intentionally limits the usage of the std, // since it will be linked with an uninstrumented version of it. -#![feature(core_intrinsics)] #![allow(invalid_value)] #![no_main] diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index ba952cdb0dc6..c86c2448cc68 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -4,12 +4,12 @@ //@ ignore-backends: gcc #![feature( repr_simd, - core_intrinsics, intrinsics, adt_const_params, unsized_const_params, generic_const_exprs )] +#![cfg_attr(old, feature(core_intrinsics))] #![allow(incomplete_features)] #[path = "../../auxiliary/minisimd.rs"] diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs-enums/rec-align-u32.rs index 058f06732b92..b86cdebfe19a 100644 --- a/tests/ui/structs-enums/rec-align-u32.rs +++ b/tests/ui/structs-enums/rec-align-u32.rs @@ -3,7 +3,7 @@ #![allow(unused_unsafe)] // Issue #2303 -#![feature(core_intrinsics, rustc_attrs)] +#![feature(rustc_attrs)] use std::mem; diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 41b196dc5c22..e49726c7d438 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -4,7 +4,7 @@ // Issue #2303 -#![feature(core_intrinsics, rustc_attrs)] +#![feature(rustc_attrs)] use std::mem; diff --git a/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs index 4d3c4e8accd8..4eda8fab1b63 100644 --- a/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs +++ b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs @@ -1,4 +1,5 @@ -#![feature(cfg_target_thread_local, thread_local)] +#![feature(cfg_target_thread_local)] +#![cfg_attr(target_thread_local, feature(thread_local))] #![crate_type = "lib"] #[cfg(target_thread_local)] diff --git a/tests/ui/threads-sendsync/thread-local-extern-static.rs b/tests/ui/threads-sendsync/thread-local-extern-static.rs index ce2a221ec2e4..0da4e398f335 100644 --- a/tests/ui/threads-sendsync/thread-local-extern-static.rs +++ b/tests/ui/threads-sendsync/thread-local-extern-static.rs @@ -2,7 +2,8 @@ //@ ignore-windows FIXME(134939): thread_local + no_mangle doesn't work on Windows //@ aux-build:thread-local-extern-static.rs -#![feature(cfg_target_thread_local, thread_local)] +#![feature(cfg_target_thread_local)] +#![cfg_attr(target_thread_local, feature(thread_local))] #[cfg(target_thread_local)] extern crate thread_local_extern_static; diff --git a/tests/ui/traits/alias/import-cross-crate.rs b/tests/ui/traits/alias/import-cross-crate.rs index 65e7c90965b8..f77aa3cd05a3 100644 --- a/tests/ui/traits/alias/import-cross-crate.rs +++ b/tests/ui/traits/alias/import-cross-crate.rs @@ -1,7 +1,6 @@ //@ run-pass //@ aux-build:greeter.rs -#![feature(trait_alias)] extern crate greeter; diff --git a/tests/ui/traits/overlap-permitted-for-marker-traits.rs b/tests/ui/traits/overlap-permitted-for-marker-traits.rs index c05e5fddae63..310516f4e4ac 100644 --- a/tests/ui/traits/overlap-permitted-for-marker-traits.rs +++ b/tests/ui/traits/overlap-permitted-for-marker-traits.rs @@ -4,7 +4,6 @@ // `MyMarker` if it is either `Debug` or `Display`. #![feature(marker_trait_attr)] -#![feature(negative_impls)] use std::fmt::{Debug, Display}; diff --git a/tests/ui/type/typeid-consistency.rs b/tests/ui/type/typeid-consistency.rs index 67ee1b6d839a..fb22ae3ac305 100644 --- a/tests/ui/type/typeid-consistency.rs +++ b/tests/ui/type/typeid-consistency.rs @@ -3,7 +3,6 @@ //@ run-pass #![allow(deprecated)] -#![feature(core_intrinsics)] //@ aux-build:typeid-consistency-aux1.rs //@ aux-build:typeid-consistency-aux2.rs diff --git a/tests/ui/typeck/type-name-intrinsic-usage-61894.rs b/tests/ui/typeck/type-name-intrinsic-usage-61894.rs index 8131bb273909..f587e5fe53f9 100644 --- a/tests/ui/typeck/type-name-intrinsic-usage-61894.rs +++ b/tests/ui/typeck/type-name-intrinsic-usage-61894.rs @@ -1,7 +1,6 @@ // https://github.com/rust-lang/rust/issues/61894 //@ run-pass -#![feature(core_intrinsics)] use std::any::type_name; From b3434a216b860433acfb2bb4cbbbe6fee184502a Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 4 Mar 2026 05:13:41 +0000 Subject: [PATCH 46/59] Prepare for merging from rust-lang/rust This updates the rust-version file to d933cf483edf1605142ac6899ff32536c0ad8b22. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 3e265317484a..90a48de0fcb0 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -ba1567989ee7774a1fb53aa680a8e4e8daa0f519 +d933cf483edf1605142ac6899ff32536c0ad8b22 From 91c7627c0f9df9624af546440bbbd0c5ba0cd268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 2 Mar 2026 09:08:05 +0100 Subject: [PATCH 47/59] Remove `cycle_fatal` query modifier This removes the `cycle_fatal` query modifier as it has no effect on its current users. The default `CycleErrorHandling::Error` mode does the same as `cycle_fatal` when the default impl of `FromCycleError` is used. The return types of queries using `cycle_fatal` however have no specialized `FromCycleError` impl. --- compiler/rustc_macros/src/query.rs | 9 --------- compiler/rustc_middle/src/queries.rs | 21 ++++---------------- compiler/rustc_middle/src/query/modifiers.rs | 5 ----- compiler/rustc_middle/src/query/plumbing.rs | 1 - compiler/rustc_query_impl/src/execution.rs | 4 ---- 5 files changed, 4 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 0a741d32ed61..8f0bfed2035c 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -144,7 +144,6 @@ struct QueryModifiers { arena_cache: Option, cache_on_disk_if: Option, cycle_delay_bug: Option, - cycle_fatal: Option, cycle_stash: Option, depth_limit: Option, desc: Desc, @@ -160,7 +159,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut arena_cache = None; let mut cache_on_disk_if = None; let mut desc = None; - let mut cycle_fatal = None; let mut cycle_delay_bug = None; let mut cycle_stash = None; let mut no_hash = None; @@ -197,8 +195,6 @@ macro_rules! try_insert { try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block }); } else if modifier == "arena_cache" { try_insert!(arena_cache = modifier); - } else if modifier == "cycle_fatal" { - try_insert!(cycle_fatal = modifier); } else if modifier == "cycle_delay_bug" { try_insert!(cycle_delay_bug = modifier); } else if modifier == "cycle_stash" { @@ -228,7 +224,6 @@ macro_rules! try_insert { arena_cache, cache_on_disk_if, desc, - cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, @@ -248,7 +243,6 @@ fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macr arena_cache, cache_on_disk_if, cycle_delay_bug, - cycle_fatal, cycle_stash, depth_limit, desc: _, @@ -266,8 +260,6 @@ fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macr let cycle_error_handling = if cycle_delay_bug.is_some() { quote! { DelayBug } - } else if cycle_fatal.is_some() { - quote! { Fatal } } else if cycle_stash.is_some() { quote! { Stash } } else { @@ -407,7 +399,6 @@ macro_rules! doc_link { doc_link!( arena_cache, - cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 932d0855c601..c5cdd7598a56 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -32,7 +32,6 @@ //! - `arena_cache`: Use an arena for in-memory caching of the query result. //! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to //! true. The query key identifier is available for use within the block, as is `tcx`. -//! - `cycle_fatal`: If a dependency cycle is detected, abort compilation with a fatal error. //! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately. //! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling. //! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed. @@ -149,11 +148,11 @@ // which memoizes and does dep-graph tracking, wrapping around the actual // `Providers` that the driver creates (using several `rustc_*` crates). // -// The result type of each query must implement `Clone`, and additionally -// `ty::query::from_cycle_error::FromCycleError`, which produces an appropriate +// The result type of each query must implement `Clone`. Additionally +// `ty::query::from_cycle_error::FromCycleError` can be implemented which produces an appropriate // placeholder (error) value if the query resulted in a query cycle. -// Queries marked with `cycle_fatal` do not need the latter implementation, -// as they will raise a fatal error on query cycles instead. +// Queries without a `FromCycleError` implementation will raise a fatal error on query +// cycles instead. rustc_queries! { /// Caches the expansion of a derive proc macro, e.g. `#[derive(Serialize)]`. /// The key is: @@ -587,7 +586,6 @@ } query is_panic_runtime(_: CrateNum) -> bool { - cycle_fatal desc { "checking if the crate is_panic_runtime" } separate_provide_extern } @@ -1318,7 +1316,6 @@ /// Return the set of (transitive) callees that may result in a recursive call to `key`, /// if we were able to walk all callees. query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx Option> { - cycle_fatal arena_cache desc { "computing (transitive) callees of `{}` that may recurse", @@ -1329,7 +1326,6 @@ /// Obtain all the calls into other local functions query mir_inliner_callees(key: ty::InstanceKind<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { - cycle_fatal desc { "computing all local function calls in `{}`", tcx.def_path_str(key.def_id()), @@ -1824,31 +1820,26 @@ } query is_compiler_builtins(_: CrateNum) -> bool { - cycle_fatal desc { "checking if the crate is_compiler_builtins" } separate_provide_extern } query has_global_allocator(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - cycle_fatal desc { "checking if the crate has_global_allocator" } separate_provide_extern } query has_alloc_error_handler(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - cycle_fatal desc { "checking if the crate has_alloc_error_handler" } separate_provide_extern } query has_panic_handler(_: CrateNum) -> bool { - cycle_fatal desc { "checking if the crate has_panic_handler" } separate_provide_extern } query is_profiler_runtime(_: CrateNum) -> bool { - cycle_fatal desc { "checking if a crate is `#![profiler_runtime]`" } separate_provide_extern } @@ -1857,22 +1848,18 @@ cache_on_disk_if { true } } query required_panic_strategy(_: CrateNum) -> Option { - cycle_fatal desc { "getting a crate's required panic strategy" } separate_provide_extern } query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { - cycle_fatal desc { "getting a crate's configured panic-in-drop strategy" } separate_provide_extern } query is_no_builtins(_: CrateNum) -> bool { - cycle_fatal desc { "getting whether a crate has `#![no_builtins]`" } separate_provide_extern } query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { - cycle_fatal desc { "getting a crate's symbol mangling version" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 44aaa6a3ce3d..c305f65a9ef3 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -28,11 +28,6 @@ /// A cycle error results in a delay_bug call pub(crate) struct cycle_delay_bug; -/// # `cycle_fatal` query modifier -/// -/// A cycle error for this query aborting the compilation with a fatal error. -pub(crate) struct cycle_fatal; - /// # `cycle_stash` query modifier /// /// A cycle error results in a stashed cycle error that can be unstashed and canceled later diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 815c8a1baab6..ae348c668fb5 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -57,7 +57,6 @@ pub enum ActiveKeyStatus<'tcx> { #[derive(Copy, Clone)] pub enum CycleErrorHandling { Error, - Fatal, DelayBug, Stash, } diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 323d40fdbaab..34be511ad312 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -131,10 +131,6 @@ fn mk_cycle<'tcx, C: QueryCache>( let guar = error.emit(); query.value_from_cycle_error(tcx, cycle_error, guar) } - CycleErrorHandling::Fatal => { - let guar = error.emit(); - guar.raise_fatal(); - } CycleErrorHandling::DelayBug => { let guar = error.delay_as_bug(); query.value_from_cycle_error(tcx, cycle_error, guar) From ee855c02aff1dfc5e609f2ff307885e8842f454c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Mar 2026 11:32:19 +0100 Subject: [PATCH 48/59] Migrate `rustc_pattern_analysis` lint to `Diagnostic` --- compiler/rustc_pattern_analysis/src/errors.rs | 6 ++++-- compiler/rustc_pattern_analysis/src/lints.rs | 10 +++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index b27e52f32bf2..25432d6ea5cd 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -131,10 +131,12 @@ pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { pub uncovered: Uncovered, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("the lint level must be set on the whole match")] #[help("it no longer has any effect to set the lint level on an individual match arm")] pub(crate) struct NonExhaustiveOmittedPatternLintOnArm { + #[primary_span] + pub span: Span, #[label("remove this attribute")] pub lint_span: Span, #[suggestion( diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs index 3da744dc8c02..5a8adf4841c4 100644 --- a/compiler/rustc_pattern_analysis/src/lints.rs +++ b/compiler/rustc_pattern_analysis/src/lints.rs @@ -92,17 +92,13 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>( let LevelAndSource { level, src, .. } = rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.arm_data); if !matches!(level, rustc_session::lint::Level::Allow) { - let decorator = NonExhaustiveOmittedPatternLintOnArm { + rcx.tcx.dcx().emit_warn(NonExhaustiveOmittedPatternLintOnArm { + span: arm.pat.data().span, lint_span: src.span(), suggest_lint_on_match: rcx.whole_match_span.map(|span| span.shrink_to_lo()), lint_level: level.as_str(), lint_name: "non_exhaustive_omitted_patterns", - }; - - use rustc_errors::LintDiagnostic; - let mut err = rcx.tcx.dcx().struct_span_warn(arm.pat.data().span, ""); - decorator.decorate_lint(&mut err); - err.emit(); + }); } } } From c29a26e37d6a42b0a46fdecb1ababfc7b269c354 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Mar 2026 12:03:39 +0100 Subject: [PATCH 49/59] Remove `LintDiagnostic` implementation on `rustc_middle::Deprecated` --- compiler/rustc_middle/src/middle/stability.rs | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index ff6baabbb29a..628d35814684 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintBuffer, LintDiagnostic, msg}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintBuffer, msg}; use rustc_feature::GateIssue; use rustc_hir::attrs::{DeprecatedSince, Deprecation}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -131,15 +131,8 @@ fn into_diag( dcx: rustc_errors::DiagCtxtHandle<'a>, level: rustc_errors::Level, ) -> Diag<'a, G> { - let mut diag = Diag::new(dcx, level, ""); - self.decorate_lint(&mut diag); - diag - } -} - -impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for Deprecated { - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { - diag.primary_message(match &self.since_kind { + let Self { sub, kind, path, note, since_kind } = self; + let mut diag = Diag::new(dcx, level, match &since_kind { DeprecatedSinceKind::InEffect => msg!( "use of deprecated {$kind} `{$path}`{$has_note -> [true] : {$note} @@ -160,21 +153,22 @@ fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) { }" ) } - }); - diag.arg("kind", self.kind); - diag.arg("path", self.path); - if let DeprecatedSinceKind::InVersion(version) = self.since_kind { + }) + .with_arg("kind", kind) + .with_arg("path", path); + if let DeprecatedSinceKind::InVersion(version) = since_kind { diag.arg("version", version); } - if let Some(note) = self.note { + if let Some(note) = note { diag.arg("has_note", true); diag.arg("note", note); } else { diag.arg("has_note", false); } - if let Some(sub) = self.sub { + if let Some(sub) = sub { diag.subdiagnostic(sub); } + diag } } From 66246a61fd5b5b9c55947ac78d0a4add0f3cc6c8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 4 Mar 2026 11:00:35 +0100 Subject: [PATCH 50/59] use `minicore` in some `run-make` tests --- src/tools/run-make-support/src/lib.rs | 3 +- .../run-make-support/src/path_helpers.rs | 6 ++++ tests/auxiliary/minicore.rs | 11 +++++++ .../avr-rjmp-offset/avr-rjmp-offsets.rs | 32 ++----------------- tests/run-make/avr-rjmp-offset/rmake.rs | 12 ++++++- tests/run-make/thumb-interworking/rmake.rs | 10 +++--- .../run-make/wasm-unexpected-features/foo.rs | 21 ++---------- .../wasm-unexpected-features/rmake.rs | 15 +++++++-- 8 files changed, 52 insertions(+), 58 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 52cc7ae9d379..a15b4bc5a5c1 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -77,7 +77,8 @@ pub mod rfs { // Path-related helpers. pub use crate::path_helpers::{ build_root, cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, - has_suffix, not_contains, path, shallow_find_directories, shallow_find_files, source_root, + has_suffix, minicore_path, not_contains, path, shallow_find_directories, shallow_find_files, + source_root, }; // Convenience helpers for running binaries and other commands. pub use crate::run::{cmd, run, run_fail, run_with_args}; diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index b766e50e523b..058bf0023268 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -40,6 +40,12 @@ pub fn build_root() -> PathBuf { env_var("BUILD_ROOT").into() } +/// Path to minicore. +#[must_use] +pub fn minicore_path() -> PathBuf { + source_root().join("tests/auxiliary/minicore.rs") +} + /// Browse the directory `path` non-recursively and return all files which respect the parameters /// outlined by `closure`. #[track_caller] diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs index 3b3472340e73..17f325d58278 100644 --- a/tests/auxiliary/minicore.rs +++ b/tests/auxiliary/minicore.rs @@ -288,6 +288,17 @@ pub mod mem { pub const fn align_of() -> usize; } +pub mod ptr { + #[inline] + #[rustc_diagnostic_item = "ptr_write_volatile"] + pub unsafe fn write_volatile(dst: *mut T, src: T) { + #[rustc_intrinsic] + pub unsafe fn volatile_store(dst: *mut T, val: T); + + unsafe { volatile_store(dst, src) }; + } +} + #[lang = "c_void"] #[repr(u8)] pub enum c_void { diff --git a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs index 07fda1f3f4a3..baea8ff77254 100644 --- a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs +++ b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs @@ -7,7 +7,8 @@ #![no_main] #![allow(internal_features)] -use minicore::ptr; +extern crate minicore; +use minicore::*; #[no_mangle] pub fn main() -> ! { @@ -21,32 +22,3 @@ pub fn main() -> ! { unsafe { ptr::write_volatile(port_b, 2) }; } } - -// FIXME: replace with proper minicore once available (#130693) -mod minicore { - #[lang = "pointee_sized"] - pub trait PointeeSized {} - - #[lang = "meta_sized"] - pub trait MetaSized: PointeeSized {} - - #[lang = "sized"] - pub trait Sized: MetaSized {} - - #[lang = "copy"] - pub trait Copy {} - impl Copy for u32 {} - impl Copy for &u32 {} - impl Copy for *mut T {} - - pub mod ptr { - #[inline] - #[rustc_diagnostic_item = "ptr_write_volatile"] - pub unsafe fn write_volatile(dst: *mut T, src: T) { - #[rustc_intrinsic] - pub unsafe fn volatile_store(dst: *mut T, val: T); - - unsafe { volatile_store(dst, src) }; - } - } -} diff --git a/tests/run-make/avr-rjmp-offset/rmake.rs b/tests/run-make/avr-rjmp-offset/rmake.rs index 86d85e89f788..c9548e3a8a8d 100644 --- a/tests/run-make/avr-rjmp-offset/rmake.rs +++ b/tests/run-make/avr-rjmp-offset/rmake.rs @@ -15,9 +15,18 @@ // crashes... so I'm going to disable this test for windows for now. //@ ignore-windows-gnu -use run_make_support::{llvm_objdump, rustc}; +use run_make_support::{llvm_objdump, minicore_path, path, rustc}; fn main() { + rustc() + .input(minicore_path()) + .crate_name("minicore") + .crate_type("rlib") + .target("avr-none") + .target_cpu("avr") + .output("libminicore.rlib") + .run(); + rustc() .input("avr-rjmp-offsets.rs") .opt_level("s") @@ -36,6 +45,7 @@ fn main() { .linker("rust-lld") .link_arg("--entry=main") .output("compiled") + .extern_("minicore", path("libminicore.rlib")) .run(); let disassembly = llvm_objdump().disassemble().input("compiled").run().stdout_utf8(); diff --git a/tests/run-make/thumb-interworking/rmake.rs b/tests/run-make/thumb-interworking/rmake.rs index 1aa39ed1ce15..f88cc87abf0a 100644 --- a/tests/run-make/thumb-interworking/rmake.rs +++ b/tests/run-make/thumb-interworking/rmake.rs @@ -1,6 +1,8 @@ //@ needs-llvm-components: arm //@ needs-rust-lld -use run_make_support::{llvm_filecheck, llvm_objdump, path, rfs, run, rustc, source_root}; +use run_make_support::{ + llvm_filecheck, llvm_objdump, minicore_path, path, rfs, run, rustc, source_root, +}; // Test a thumb target calling arm functions. Doing so requires switching from thumb mode to arm // mode, calling the arm code, then switching back to thumb mode. Depending on the thumb version, @@ -26,20 +28,18 @@ fn main() { fn helper(prefix: &str, target: &str) { rustc() - .input(source_root().join("tests/auxiliary/minicore.rs")) + .input(minicore_path()) .crate_name("minicore") .crate_type("rlib") .target(target) .output("libminicore.rlib") .run(); - let minicore = path("libminicore.rlib"); rustc() .input("main.rs") .panic("abort") .link_arg("-Tlink.ld") - .arg("--extern") - .arg(format!("minicore={}", minicore.display())) + .extern_("minicore", path("libminicore.rlib")) .target(target) .output(prefix) .run(); diff --git a/tests/run-make/wasm-unexpected-features/foo.rs b/tests/run-make/wasm-unexpected-features/foo.rs index 5c7aa2d61904..20c7bc0839ec 100644 --- a/tests/run-make/wasm-unexpected-features/foo.rs +++ b/tests/run-make/wasm-unexpected-features/foo.rs @@ -4,6 +4,9 @@ #![needs_allocator] #![allow(internal_features)] +extern crate minicore; +use minicore::*; + #[rustc_std_internal_symbol] unsafe fn __rust_alloc(_size: usize, _align: usize) -> *mut u8 { 0 as *mut u8 @@ -23,21 +26,3 @@ extern "C" fn init() { __rust_alloc_error_handler(0, 0); } } - -mod minicore { - #[lang = "pointee_sized"] - pub trait PointeeSized {} - - #[lang = "meta_sized"] - pub trait MetaSized: PointeeSized {} - - #[lang = "sized"] - pub trait Sized: MetaSized {} - - #[lang = "copy"] - pub trait Copy {} - impl Copy for u8 {} - - #[lang = "drop_in_place"] - fn drop_in_place(_: *mut T) {} -} diff --git a/tests/run-make/wasm-unexpected-features/rmake.rs b/tests/run-make/wasm-unexpected-features/rmake.rs index 01eff54e823c..4bd771598f89 100644 --- a/tests/run-make/wasm-unexpected-features/rmake.rs +++ b/tests/run-make/wasm-unexpected-features/rmake.rs @@ -1,10 +1,18 @@ -//@ only-wasm32-wasip1 - +//@ needs-rust-lld use std::path::Path; -use run_make_support::{rfs, rustc, wasmparser}; +use run_make_support::{minicore_path, path, rfs, rustc, wasmparser}; fn main() { + rustc() + .input(minicore_path()) + .crate_name("minicore") + .crate_type("rlib") + .target("wasm32-wasip1") + .target_cpu("mvp") + .output("libminicore.rlib") + .run(); + rustc() .input("foo.rs") .target("wasm32-wasip1") @@ -13,6 +21,7 @@ fn main() { .lto("fat") .linker_plugin_lto("on") .link_arg("--import-memory") + .extern_("minicore", path("libminicore.rlib")) .run(); verify_features(Path::new("foo.wasm")); } From b6fb48654e084dd0ae3323a6eaccc89ff8516724 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 4 Mar 2026 13:26:17 +0100 Subject: [PATCH 51/59] add `rustc_minicore` helper function --- .../src/external_deps/rustc.rs | 33 ++++++++++++++++++- src/tools/run-make-support/src/lib.rs | 5 ++- .../run-make-support/src/path_helpers.rs | 6 ---- tests/run-make/avr-rjmp-offset/rmake.rs | 11 ++----- tests/run-make/thumb-interworking/rmake.rs | 10 ++---- .../wasm-unexpected-features/rmake.rs | 11 ++----- 6 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index b461a24a0616..2fa680a8e233 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -4,7 +4,7 @@ use crate::command::Command; use crate::env::env_var; -use crate::path_helpers::cwd; +use crate::path_helpers::{cwd, source_root}; use crate::util::set_host_compiler_dylib_path; use crate::{is_aix, is_darwin, is_windows, is_windows_msvc, target, uname}; @@ -22,6 +22,37 @@ pub fn bare_rustc() -> Rustc { Rustc::bare() } +/// Construct a `rustc` invocation for building `minicore`. +/// +/// This function: +/// +/// - adds `tests/auxiliary/minicore.rs` as an input +/// - sets the crate name to `"minicore"` +/// - sets the crate type to `rlib` +/// +/// # Example +/// +/// ```ignore (illustrative) +/// rustc_minicore().target("wasm32-wasip1").target_cpu("mvp").output("libminicore.rlib").run(); +/// +/// rustc() +/// .input("foo.rs") +/// .target("wasm32-wasip1") +/// .target_cpu("mvp") +/// .extern_("minicore", path("libminicore.rlib")) +/// // ... +/// .run() +/// ``` +#[track_caller] +pub fn rustc_minicore() -> Rustc { + let mut builder = rustc(); + + let minicore_path = source_root().join("tests/auxiliary/minicore.rs"); + builder.input(minicore_path).crate_name("minicore").crate_type("rlib"); + + builder +} + /// A `rustc` invocation builder. #[derive(Debug)] #[must_use] diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index a15b4bc5a5c1..ba413724c2fe 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -72,13 +72,12 @@ pub mod rfs { llvm_readobj, }; pub use crate::external_deps::python::python_command; -pub use crate::external_deps::rustc::{self, Rustc, bare_rustc, rustc, rustc_path}; +pub use crate::external_deps::rustc::{self, Rustc, bare_rustc, rustc, rustc_minicore, rustc_path}; pub use crate::external_deps::rustdoc::{Rustdoc, bare_rustdoc, rustdoc}; // Path-related helpers. pub use crate::path_helpers::{ build_root, cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, - has_suffix, minicore_path, not_contains, path, shallow_find_directories, shallow_find_files, - source_root, + has_suffix, not_contains, path, shallow_find_directories, shallow_find_files, source_root, }; // Convenience helpers for running binaries and other commands. pub use crate::run::{cmd, run, run_fail, run_with_args}; diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index 058bf0023268..b766e50e523b 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -40,12 +40,6 @@ pub fn build_root() -> PathBuf { env_var("BUILD_ROOT").into() } -/// Path to minicore. -#[must_use] -pub fn minicore_path() -> PathBuf { - source_root().join("tests/auxiliary/minicore.rs") -} - /// Browse the directory `path` non-recursively and return all files which respect the parameters /// outlined by `closure`. #[track_caller] diff --git a/tests/run-make/avr-rjmp-offset/rmake.rs b/tests/run-make/avr-rjmp-offset/rmake.rs index c9548e3a8a8d..a4a219436ad2 100644 --- a/tests/run-make/avr-rjmp-offset/rmake.rs +++ b/tests/run-make/avr-rjmp-offset/rmake.rs @@ -15,17 +15,10 @@ // crashes... so I'm going to disable this test for windows for now. //@ ignore-windows-gnu -use run_make_support::{llvm_objdump, minicore_path, path, rustc}; +use run_make_support::{llvm_objdump, path, rustc, rustc_minicore}; fn main() { - rustc() - .input(minicore_path()) - .crate_name("minicore") - .crate_type("rlib") - .target("avr-none") - .target_cpu("avr") - .output("libminicore.rlib") - .run(); + rustc_minicore().target("avr-none").target_cpu("avr").output("libminicore.rlib").run(); rustc() .input("avr-rjmp-offsets.rs") diff --git a/tests/run-make/thumb-interworking/rmake.rs b/tests/run-make/thumb-interworking/rmake.rs index f88cc87abf0a..05ff73c78efb 100644 --- a/tests/run-make/thumb-interworking/rmake.rs +++ b/tests/run-make/thumb-interworking/rmake.rs @@ -1,7 +1,7 @@ //@ needs-llvm-components: arm //@ needs-rust-lld use run_make_support::{ - llvm_filecheck, llvm_objdump, minicore_path, path, rfs, run, rustc, source_root, + llvm_filecheck, llvm_objdump, path, rfs, run, rustc, rustc_minicore, source_root, }; // Test a thumb target calling arm functions. Doing so requires switching from thumb mode to arm @@ -27,13 +27,7 @@ fn main() { } fn helper(prefix: &str, target: &str) { - rustc() - .input(minicore_path()) - .crate_name("minicore") - .crate_type("rlib") - .target(target) - .output("libminicore.rlib") - .run(); + rustc_minicore().target(target).output("libminicore.rlib").run(); rustc() .input("main.rs") diff --git a/tests/run-make/wasm-unexpected-features/rmake.rs b/tests/run-make/wasm-unexpected-features/rmake.rs index 4bd771598f89..44c6f3522267 100644 --- a/tests/run-make/wasm-unexpected-features/rmake.rs +++ b/tests/run-make/wasm-unexpected-features/rmake.rs @@ -1,17 +1,10 @@ //@ needs-rust-lld use std::path::Path; -use run_make_support::{minicore_path, path, rfs, rustc, wasmparser}; +use run_make_support::{path, rfs, rustc, rustc_minicore, wasmparser}; fn main() { - rustc() - .input(minicore_path()) - .crate_name("minicore") - .crate_type("rlib") - .target("wasm32-wasip1") - .target_cpu("mvp") - .output("libminicore.rlib") - .run(); + rustc_minicore().target("wasm32-wasip1").target_cpu("mvp").output("libminicore.rlib").run(); rustc() .input("foo.rs") From c9529f361ca0e17239566c9e4723ecd42f8deb17 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 4 Mar 2026 22:09:02 +0800 Subject: [PATCH 52/59] triagebot: remove a ping for `jieyouxu` --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index b1675e00f0df..6da56b8ed253 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1371,7 +1371,7 @@ cc = ["@ehuss"] [mentions."src/doc/rustc-dev-guide"] message = "The rustc-dev-guide subtree was changed. If this PR *only* touches the dev guide consider submitting a PR directly to [rust-lang/rustc-dev-guide](https://github.com/rust-lang/rustc-dev-guide/pulls) otherwise thank you for updating the dev guide with your changes." -cc = ["@BoxyUwU", "@jieyouxu", "@tshepang"] +cc = ["@BoxyUwU", "@tshepang"] [mentions."compiler/rustc_passes/src/check_attr.rs"] cc = ["@jdonszelmann", "@JonathanBrouwer"] From 7ceb8ea1b0317488e7e395eff705e83b4da89adc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Mar 2026 12:22:47 +0100 Subject: [PATCH 53/59] Remove unused `LintDiagnostic` trait --- compiler/rustc_errors/src/decorate_diag.rs | 2 +- compiler/rustc_errors/src/diagnostic.rs | 8 -- compiler/rustc_errors/src/lib.rs | 2 +- .../diagnostic-derive-inline.rs | 29 +---- .../diagnostic-derive-inline.stderr | 110 ++++++------------ 5 files changed, 38 insertions(+), 113 deletions(-) diff --git a/compiler/rustc_errors/src/decorate_diag.rs b/compiler/rustc_errors/src/decorate_diag.rs index 7e53b8195d5b..a11082e29663 100644 --- a/compiler/rustc_errors/src/decorate_diag.rs +++ b/compiler/rustc_errors/src/decorate_diag.rs @@ -7,7 +7,7 @@ use crate::{Diag, DiagCtxtHandle, Diagnostic, Level}; -/// We can't implement `LintDiagnostic` for `BuiltinLintDiag`, because decorating some of its +/// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its /// variants requires types we don't have yet. So, handle that case separately. pub enum DecorateDiagCompat { Dynamic(Box FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + 'static>), diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 888009bf9d4c..f68e6000ddf9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -138,14 +138,6 @@ pub trait Subdiagnostic fn add_to_diag(self, diag: &mut Diag<'_, G>); } -/// Trait implemented by lint types. This should not be implemented manually. Instead, use -/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. -#[rustc_diagnostic_item = "LintDiagnostic"] -pub trait LintDiagnostic<'a, G: EmissionGuarantee> { - /// Decorate a lint with the information from this type. - fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>); -} - #[derive(Clone, Debug, Encodable, Decodable)] pub(crate) struct DiagLocation { file: Cow<'static, str>, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4ef4d5807463..743c90bd2884 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -40,7 +40,7 @@ pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ BugAbort, Diag, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, FatalAbort, - LintDiagnostic, StringPart, Subdiag, Subdiagnostic, + StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs index 759a9412f769..26d92126fe87 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs @@ -20,7 +20,7 @@ use rustc_span::Span; extern crate rustc_macros; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; extern crate rustc_middle; use rustc_middle::ty::Ty; @@ -495,18 +495,6 @@ struct LabelWithTrailingList { span: Span, } -#[derive(LintDiagnostic)] -#[diag("this is an example message")] -struct LintsGood {} - -#[derive(LintDiagnostic)] -#[diag("this is an example message")] -struct PrimarySpanOnLint { - #[primary_span] - //~^ ERROR `#[primary_span]` is not a valid attribute - span: Span, -} - #[derive(Diagnostic)] #[diag("this is an example message", code = E0123)] struct ErrorWithMultiSpan { @@ -542,13 +530,6 @@ struct WarnAttribute {} //~| ERROR cannot find attribute `lint` in this scope struct LintAttributeOnSessionDiag {} -#[derive(LintDiagnostic)] -#[lint("this is an example message", code = E0123)] -//~^ ERROR `#[lint(...)]` is not a valid attribute -//~| ERROR diagnostic message not specified -//~| ERROR cannot find attribute `lint` in this scope -struct LintAttributeOnLintDiag {} - #[derive(Diagnostic)] #[diag("this is an example message", code = E0123)] struct DuplicatedSuggestionCode { @@ -670,14 +651,6 @@ struct SubdiagnosticBadLitStr { note: Note, } -#[derive(LintDiagnostic)] -#[diag("this is an example message")] -struct SubdiagnosticEagerLint { - #[subdiagnostic(eager)] - //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute - note: Note, -} - #[derive(Diagnostic)] #[diag("this is an example message")] struct SubdiagnosticEagerFormerlyCorrect { diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr index b32235c02b07..48138fc9fb55 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr @@ -300,22 +300,14 @@ error: derive(Diagnostic): no nested attribute expected here LL | #[label("with a label", foo("..."))] | ^^^ -error: derive(Diagnostic): `#[primary_span]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:505:5 - | -LL | #[primary_span] - | ^ - | - = help: the `primary_span` field attribute is not valid for lint diagnostics - error: derive(Diagnostic): `#[error(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:525:1 + --> $DIR/diagnostic-derive-inline.rs:513:1 | LL | #[error("this is an example message", code = E0123)] | ^ error: derive(Diagnostic): diagnostic message not specified - --> $DIR/diagnostic-derive-inline.rs:525:1 + --> $DIR/diagnostic-derive-inline.rs:513:1 | LL | #[error("this is an example message", code = E0123)] | ^ @@ -323,13 +315,13 @@ LL | #[error("this is an example message", code = E0123)] = help: specify the message as the first argument to the `#[diag(...)]` attribute, such as `#[diag("Example error")]` error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:532:1 + --> $DIR/diagnostic-derive-inline.rs:520:1 | LL | #[warn_("this is an example message", code = E0123)] | ^ error: derive(Diagnostic): diagnostic message not specified - --> $DIR/diagnostic-derive-inline.rs:532:1 + --> $DIR/diagnostic-derive-inline.rs:520:1 | LL | #[warn_("this is an example message", code = E0123)] | ^ @@ -337,27 +329,13 @@ LL | #[warn_("this is an example message", code = E0123)] = help: specify the message as the first argument to the `#[diag(...)]` attribute, such as `#[diag("Example error")]` error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:539:1 + --> $DIR/diagnostic-derive-inline.rs:527:1 | LL | #[lint("this is an example message", code = E0123)] | ^ error: derive(Diagnostic): diagnostic message not specified - --> $DIR/diagnostic-derive-inline.rs:539:1 - | -LL | #[lint("this is an example message", code = E0123)] - | ^ - | - = help: specify the message as the first argument to the `#[diag(...)]` attribute, such as `#[diag("Example error")]` - -error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:546:1 - | -LL | #[lint("this is an example message", code = E0123)] - | ^ - -error: derive(Diagnostic): diagnostic message not specified - --> $DIR/diagnostic-derive-inline.rs:546:1 + --> $DIR/diagnostic-derive-inline.rs:527:1 | LL | #[lint("this is an example message", code = E0123)] | ^ @@ -365,19 +343,19 @@ LL | #[lint("this is an example message", code = E0123)] = help: specify the message as the first argument to the `#[diag(...)]` attribute, such as `#[diag("Example error")]` error: derive(Diagnostic): attribute specified multiple times - --> $DIR/diagnostic-derive-inline.rs:555:53 + --> $DIR/diagnostic-derive-inline.rs:536:53 | LL | #[suggestion("with a suggestion", code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive-inline.rs:555:39 + --> $DIR/diagnostic-derive-inline.rs:536:39 | LL | #[suggestion("with a suggestion", code = "...", code = ",,,")] | ^^^^ error: derive(Diagnostic): wrong types for suggestion - --> $DIR/diagnostic-derive-inline.rs:564:24 + --> $DIR/diagnostic-derive-inline.rs:545:24 | LL | suggestion: (Span, usize), | ^^^^^ @@ -385,7 +363,7 @@ LL | suggestion: (Span, usize), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: derive(Diagnostic): wrong types for suggestion - --> $DIR/diagnostic-derive-inline.rs:572:17 + --> $DIR/diagnostic-derive-inline.rs:553:17 | LL | suggestion: (Span,), | ^^^^^^^ @@ -393,13 +371,13 @@ LL | suggestion: (Span,), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: derive(Diagnostic): suggestion without `code = "..."` - --> $DIR/diagnostic-derive-inline.rs:579:5 + --> $DIR/diagnostic-derive-inline.rs:560:5 | LL | #[suggestion("with a suggestion")] | ^ error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:586:1 + --> $DIR/diagnostic-derive-inline.rs:567:1 | LL | #[multipart_suggestion("with a suggestion")] | ^ @@ -407,7 +385,7 @@ LL | #[multipart_suggestion("with a suggestion")] = help: consider creating a `Subdiagnostic` instead error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:589:1 + --> $DIR/diagnostic-derive-inline.rs:570:1 | LL | #[multipart_suggestion()] | ^ @@ -415,7 +393,7 @@ LL | #[multipart_suggestion()] = help: consider creating a `Subdiagnostic` instead error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:593:5 + --> $DIR/diagnostic-derive-inline.rs:574:5 | LL | #[multipart_suggestion("with a suggestion")] | ^ @@ -423,7 +401,7 @@ LL | #[multipart_suggestion("with a suggestion")] = help: consider creating a `Subdiagnostic` instead error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:601:1 + --> $DIR/diagnostic-derive-inline.rs:582:1 | LL | #[suggestion("with a suggestion", code = "...")] | ^ @@ -431,7 +409,7 @@ LL | #[suggestion("with a suggestion", code = "...")] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: derive(Diagnostic): `#[label]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:610:1 + --> $DIR/diagnostic-derive-inline.rs:591:1 | LL | #[label] | ^ @@ -439,73 +417,67 @@ LL | #[label] = help: subdiagnostic message is missing error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:644:5 + --> $DIR/diagnostic-derive-inline.rs:625:5 | LL | #[subdiagnostic(bad)] | ^ error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:652:5 + --> $DIR/diagnostic-derive-inline.rs:633:5 | LL | #[subdiagnostic = "bad"] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:660:5 + --> $DIR/diagnostic-derive-inline.rs:641:5 | LL | #[subdiagnostic(bad, bad)] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:668:5 + --> $DIR/diagnostic-derive-inline.rs:649:5 | LL | #[subdiagnostic("bad")] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:676:5 + --> $DIR/diagnostic-derive-inline.rs:657:5 | LL | #[subdiagnostic(eager)] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:684:5 - | -LL | #[subdiagnostic(eager)] - | ^ - -error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:705:5 + --> $DIR/diagnostic-derive-inline.rs:678:5 | LL | #[subdiagnostic(eager)] | ^ error: derive(Diagnostic): expected at least one string literal for `code(...)` - --> $DIR/diagnostic-derive-inline.rs:736:44 + --> $DIR/diagnostic-derive-inline.rs:709:44 | LL | #[suggestion("with a suggestion", code())] | ^ error: derive(Diagnostic): `code(...)` must contain only string literals - --> $DIR/diagnostic-derive-inline.rs:744:44 + --> $DIR/diagnostic-derive-inline.rs:717:44 | LL | #[suggestion("with a suggestion", code(foo))] | ^^^ error: unexpected token, expected `)` - --> $DIR/diagnostic-derive-inline.rs:744:44 + --> $DIR/diagnostic-derive-inline.rs:717:44 | LL | #[suggestion("with a suggestion", code(foo))] | ^^^ error: expected string literal - --> $DIR/diagnostic-derive-inline.rs:753:46 + --> $DIR/diagnostic-derive-inline.rs:726:46 | LL | #[suggestion("with a suggestion", code = 3)] | ^ error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:768:5 + --> $DIR/diagnostic-derive-inline.rs:741:5 | LL | #[suggestion("with a suggestion", code = "")] | ^ @@ -515,7 +487,7 @@ LL | #[suggestion("with a suggestion", code = "")] = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]` error: derive(Diagnostic): Variable `nosub` not found in diagnostic - --> $DIR/diagnostic-derive-inline.rs:780:8 + --> $DIR/diagnostic-derive-inline.rs:753:8 | LL | #[diag("does not exist: {$nosub}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -535,7 +507,7 @@ LL | #[nonsense] | ^^^^^^^^ error: cannot find attribute `error` in this scope - --> $DIR/diagnostic-derive-inline.rs:525:3 + --> $DIR/diagnostic-derive-inline.rs:513:3 | LL | #[error("this is an example message", code = E0123)] | ^^^^^ @@ -547,7 +519,7 @@ LL | struct ErrorAttribute {} | error: cannot find attribute `warn_` in this scope - --> $DIR/diagnostic-derive-inline.rs:532:3 + --> $DIR/diagnostic-derive-inline.rs:520:3 | LL | #[warn_("this is an example message", code = E0123)] | ^^^^^ @@ -559,19 +531,7 @@ LL + #[warn("this is an example message", code = E0123)] | error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive-inline.rs:539:3 - | -LL | #[lint("this is an example message", code = E0123)] - | ^^^^ - | -help: a built-in attribute with a similar name exists - | -LL - #[lint("this is an example message", code = E0123)] -LL + #[link("this is an example message", code = E0123)] - | - -error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive-inline.rs:546:3 + --> $DIR/diagnostic-derive-inline.rs:527:3 | LL | #[lint("this is an example message", code = E0123)] | ^^^^ @@ -583,7 +543,7 @@ LL + #[link("this is an example message", code = E0123)] | error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive-inline.rs:586:3 + --> $DIR/diagnostic-derive-inline.rs:567:3 | LL | #[multipart_suggestion("with a suggestion")] | ^^^^^^^^^^^^^^^^^^^^ @@ -595,7 +555,7 @@ LL | struct MultipartSuggestion { | error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive-inline.rs:589:3 + --> $DIR/diagnostic-derive-inline.rs:570:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ @@ -607,7 +567,7 @@ LL | struct MultipartSuggestion { | error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive-inline.rs:593:7 + --> $DIR/diagnostic-derive-inline.rs:574:7 | LL | #[multipart_suggestion("with a suggestion")] | ^^^^^^^^^^^^^^^^^^^^ @@ -636,6 +596,6 @@ note: required by a bound in `Diag::<'a, G>::arg` = note: in this macro invocation = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 81 previous errors +error: aborting due to 76 previous errors For more information about this error, try `rustc --explain E0277`. From 828398e986d011bbe4a16ae019fc7435c5fdf8dd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Mar 2026 13:41:36 +0100 Subject: [PATCH 54/59] Remove `LintDiagnostic` derive proc-macro --- .../src/diagnostics/diagnostic.rs | 54 +------- .../src/diagnostics/diagnostic_builder.rs | 125 +++++++----------- compiler/rustc_macros/src/diagnostics/mod.rs | 36 +---- compiler/rustc_macros/src/lib.rs | 19 --- 4 files changed, 52 insertions(+), 182 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index dc8231e5f0b0..2f7c3cc6a46d 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -4,7 +4,7 @@ use quote::quote; use synstructure::Structure; -use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind; +use crate::diagnostics::diagnostic_builder::each_variant; use crate::diagnostics::error::DiagnosticDeriveError; /// The central struct for constructing the `into_diag` method from an annotated struct. @@ -19,8 +19,7 @@ pub(crate) fn new(structure: Structure<'a>) -> Self { pub(crate) fn into_tokens(self) -> TokenStream { let DiagnosticDerive { mut structure } = self; - let kind = DiagnosticDeriveKind::Diagnostic; - let implementation = kind.each_variant(&mut structure, |mut builder, variant| { + let implementation = each_variant(&mut structure, |mut builder, variant| { let preamble = builder.preamble(variant); let body = builder.body(variant); @@ -64,52 +63,3 @@ fn into_diag( }) } } - -/// The central struct for constructing the `decorate_lint` method from an annotated struct. -pub(crate) struct LintDiagnosticDerive<'a> { - structure: Structure<'a>, -} - -impl<'a> LintDiagnosticDerive<'a> { - pub(crate) fn new(structure: Structure<'a>) -> Self { - Self { structure } - } - - pub(crate) fn into_tokens(self) -> TokenStream { - let LintDiagnosticDerive { mut structure } = self; - let kind = DiagnosticDeriveKind::LintDiagnostic; - let implementation = kind.each_variant(&mut structure, |mut builder, variant| { - let preamble = builder.preamble(variant); - let body = builder.body(variant); - - let Some(message) = builder.primary_message() else { - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); - }; - let message = message.diag_message(Some(variant)); - let primary_message = quote! { - diag.primary_message(#message); - }; - - let formatting_init = &builder.formatting_init; - quote! { - #primary_message - #preamble - #formatting_init - #body - diag - } - }); - - structure.gen_impl(quote! { - gen impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for @Self { - #[track_caller] - fn decorate_lint<'__b>( - self, - diag: &'__b mut rustc_errors::Diag<'__a, ()> - ) { - #implementation; - } - } - }) - } -} diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index de8ee42caf45..e335037f2c4c 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -18,20 +18,54 @@ should_generate_arg, type_is_bool, type_is_unit, type_matches_path, }; -/// What kind of diagnostic is being derived - a fatal/error/warning or a lint? -#[derive(Clone, Copy, PartialEq, Eq)] -pub(crate) enum DiagnosticDeriveKind { - Diagnostic, - LintDiagnostic, +pub(crate) fn each_variant<'s, F>(structure: &mut Structure<'s>, f: F) -> TokenStream +where + F: for<'v> Fn(DiagnosticDeriveVariantBuilder, &VariantInfo<'v>) -> TokenStream, +{ + let ast = structure.ast(); + let span = ast.span().unwrap(); + match ast.data { + syn::Data::Struct(..) | syn::Data::Enum(..) => (), + syn::Data::Union(..) => { + span_err(span, "diagnostic derives can only be used on structs and enums").emit(); + } + } + + if matches!(ast.data, syn::Data::Enum(..)) { + for attr in &ast.attrs { + span_err(attr.span().unwrap(), "unsupported type attribute for diagnostic derive enum") + .emit(); + } + } + + structure.bind_with(|_| synstructure::BindStyle::Move); + let variants = structure.each_variant(|variant| { + let span = match structure.ast().data { + syn::Data::Struct(..) => span, + // There isn't a good way to get the span of the variant, so the variant's + // name will need to do. + _ => variant.ast().ident.span().unwrap(), + }; + let builder = DiagnosticDeriveVariantBuilder { + span, + field_map: build_field_mapping(variant), + formatting_init: TokenStream::new(), + message: None, + code: None, + }; + f(builder, variant) + }); + + quote! { + match self { + #variants + } + } } /// Tracks persistent information required for a specific variant when building up individual calls -/// to diagnostic methods for generated diagnostic derives - both `Diagnostic` for -/// fatal/errors/warnings and `LintDiagnostic` for lints. +/// to diagnostic methods for generated diagnostic derives. pub(crate) struct DiagnosticDeriveVariantBuilder { - /// The kind for the entire type. - pub kind: DiagnosticDeriveKind, - /// Initialization of format strings for code suggestions. pub formatting_init: TokenStream, @@ -51,60 +85,6 @@ pub(crate) struct DiagnosticDeriveVariantBuilder { pub code: SpannedOption<()>, } -impl DiagnosticDeriveKind { - /// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the - /// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions - /// or attributes on the type itself when input is an enum. - pub(crate) fn each_variant<'s, F>(self, structure: &mut Structure<'s>, f: F) -> TokenStream - where - F: for<'v> Fn(DiagnosticDeriveVariantBuilder, &VariantInfo<'v>) -> TokenStream, - { - let ast = structure.ast(); - let span = ast.span().unwrap(); - match ast.data { - syn::Data::Struct(..) | syn::Data::Enum(..) => (), - syn::Data::Union(..) => { - span_err(span, "diagnostic derives can only be used on structs and enums").emit(); - } - } - - if matches!(ast.data, syn::Data::Enum(..)) { - for attr in &ast.attrs { - span_err( - attr.span().unwrap(), - "unsupported type attribute for diagnostic derive enum", - ) - .emit(); - } - } - - structure.bind_with(|_| synstructure::BindStyle::Move); - let variants = structure.each_variant(|variant| { - let span = match structure.ast().data { - syn::Data::Struct(..) => span, - // There isn't a good way to get the span of the variant, so the variant's - // name will need to do. - _ => variant.ast().ident.span().unwrap(), - }; - let builder = DiagnosticDeriveVariantBuilder { - kind: self, - span, - field_map: build_field_mapping(variant), - formatting_init: TokenStream::new(), - message: None, - code: None, - }; - f(builder, variant) - }); - - quote! { - match self { - #variants - } - } - } -} - impl DiagnosticDeriveVariantBuilder { pub(crate) fn primary_message(&self) -> Option<&Message> { match self.message.as_ref() { @@ -358,20 +338,11 @@ fn generate_inner_field_code( // `arg` call will not be generated. (Meta::Path(_), "skip_arg") => return Ok(quote! {}), (Meta::Path(_), "primary_span") => { - match self.kind { - DiagnosticDeriveKind::Diagnostic => { - report_error_if_not_applied_to_span(attr, &info)?; + report_error_if_not_applied_to_span(attr, &info)?; - return Ok(quote! { - diag.span(#binding); - }); - } - DiagnosticDeriveKind::LintDiagnostic => { - throw_invalid_attr!(attr, |diag| { - diag.help("the `primary_span` field attribute is not valid for lint diagnostics") - }) - } - } + return Ok(quote! { + diag.span(#binding); + }); } (Meta::Path(_), "subdiagnostic") => { return Ok(quote! { diag.subdiagnostic(#binding); }); diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index c0512e86bbcb..a5828cd715a8 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -6,7 +6,7 @@ mod subdiagnostic; mod utils; -use diagnostic::{DiagnosticDerive, LintDiagnosticDerive}; +use diagnostic::DiagnosticDerive; pub(super) use msg_macro::msg_macro; use proc_macro2::TokenStream; use subdiagnostic::SubdiagnosticDerive; @@ -51,38 +51,6 @@ pub(super) fn diagnostic_derive(s: Structure<'_>) -> TokenStream { DiagnosticDerive::new(s).into_tokens() } -/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct, -/// independent from the actual lint emitting code. -/// -/// ```ignore (rust) -/// #[derive(LintDiagnostic)] -/// #[diag("unused attribute")] -/// pub(crate) struct UnusedAttribute { -/// #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] -/// pub this: Span, -/// #[note("attribute also specified here")] -/// pub other: Span, -/// #[warning( -/// "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" -/// )] -/// pub warning: bool, -/// } -/// ``` -/// -/// Then, later, to emit the error: -/// -/// ```ignore (rust) -/// cx.emit_span_lint(UNUSED_ATTRIBUTES, span, UnusedAttribute { -/// ... -/// }); -/// ``` -/// -/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`: -/// -pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { - LintDiagnosticDerive::new(s).into_tokens() -} - /// Implements `#[derive(Subdiagnostic)]`, which allows for labels, notes, helps and /// suggestions to be specified as a structs or enums, independent from the actual diagnostics /// emitting code or diagnostic derives. @@ -99,7 +67,7 @@ pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// Then, later, use the subdiagnostic in a diagnostic: /// /// ```ignore (rust) -/// #[derive(LintDiagnostic)] +/// #[derive(Diagnostic)] /// #[diag("unused doc comment")] /// pub(crate) struct BuiltinUnusedDocComment<'a> { /// pub kind: &'a str, diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index d7f75e08bac8..44969908b3f4 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -196,25 +196,6 @@ pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream { suggestion_hidden, suggestion_verbose)] => diagnostics::diagnostic_derive ); -decl_derive!( - [LintDiagnostic, attributes( - // struct attributes - diag, - help, - help_once, - note, - note_once, - warning, - // field attributes - skip_arg, - primary_span, - label, - subdiagnostic, - suggestion, - suggestion_short, - suggestion_hidden, - suggestion_verbose)] => diagnostics::lint_diagnostic_derive -); decl_derive!( [Subdiagnostic, attributes( // struct/variant attributes From d9ca8c9391179bf6d5e46f1e5ac063335159bf1a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Mar 2026 13:59:38 +0100 Subject: [PATCH 55/59] Update `rustc-dev-guide` to remove mentions of `LintDiagnostic` --- .../src/diagnostics/diagnostic-structs.md | 13 ++++++------- .../rustc-dev-guide/src/diagnostics/translation.md | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index a99f6a2849c3..a3a7a11258c8 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -1,6 +1,6 @@ # Diagnostic and subdiagnostic structs -rustc has three diagnostic traits that can be used to create diagnostics: -`Diagnostic`, `LintDiagnostic`, and `Subdiagnostic`. +rustc has two diagnostic traits that can be used to create diagnostics: +`Diagnostic` and `Subdiagnostic`. For simple diagnostics, derived impls can be used, e.g. `#[derive(Diagnostic)]`. They are only suitable for simple diagnostics that @@ -8,12 +8,12 @@ don't require much logic in deciding whether or not to add additional subdiagnos In cases where diagnostics require more complex or dynamic behavior, such as conditionally adding subdiagnostics, customizing the rendering logic, or selecting messages at runtime, you will need to manually implement -the corresponding trait (`Diagnostic`, `LintDiagnostic`, or `Subdiagnostic`). +the corresponding trait (`Diagnostic` or `Subdiagnostic`). This approach provides greater flexibility and is recommended for diagnostics that go beyond simple, static structures. Diagnostic can be translated into different languages. -## `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` +## `#[derive(Diagnostic)]` Consider the [definition][defn] of the "field already declared" diagnostic shown below: @@ -123,8 +123,8 @@ tcx.dcx().emit_err(FieldAlreadyDeclared { }); ``` -### Reference for `#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` -`#[derive(Diagnostic)]` and `#[derive(LintDiagnostic)]` support the following attributes: +### Reference for `#[derive(Diagnostic)]` +`#[derive(Diagnostic)]` supports the following attributes: - `#[diag("message", code = "...")]` - _Applied to struct or enum variant._ @@ -171,7 +171,6 @@ tcx.dcx().emit_err(FieldAlreadyDeclared { - Adds the subdiagnostic represented by the subdiagnostic struct. - `#[primary_span]` (_Optional_) - _Applied to `Span` fields on `Subdiagnostic`s. - Not used for `LintDiagnostic`s._ - Indicates the primary span of the diagnostic. - `#[skip_arg]` (_Optional_) - _Applied to any field._ diff --git a/src/doc/rustc-dev-guide/src/diagnostics/translation.md b/src/doc/rustc-dev-guide/src/diagnostics/translation.md index 88526ec1c5c7..cf95727e2a67 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/translation.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/translation.md @@ -32,7 +32,7 @@ There are two ways of writing translatable diagnostics: deciding to emit subdiagnostics and can therefore be represented as diagnostic structs). See [the diagnostic and subdiagnostic structs documentation](./diagnostic-structs.md). 2. Using typed identifiers with `Diag` APIs (in - `Diagnostic` or `Subdiagnostic` or `LintDiagnostic` implementations). + `Diagnostic` or `Subdiagnostic` implementations). When adding or changing a translatable diagnostic, you don't need to worry about the translations. From e805d8c961d72112daebdf0e572d48e4c6281f0b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 4 Mar 2026 14:12:11 +0100 Subject: [PATCH 56/59] Remove mentions of `LintDiagnostic` --- compiler/rustc_middle/src/lint.rs | 4 ++-- compiler/rustc_pattern_analysis/src/errors.rs | 3 +-- .../ui/lint/decorate-ice/decorate-def-path-str-ice.rs | 11 +++++------ 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 7347fe6d9d5e..223b47c9044b 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -492,8 +492,8 @@ fn lint_level_impl( /// - [`TyCtxt::node_lint`] /// - `LintContext::opt_span_lint` /// -/// This function will replace `lint_level` once all `LintDiagnostic` items have been migrated to -/// `Diagnostic`. +/// This function will replace `lint_level` once all its callers have been replaced +/// with `diag_lint_level`. #[track_caller] pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( sess: &'a Session, diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index 25432d6ea5cd..514d1e2a9729 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -109,8 +109,7 @@ impl Subdiagnostic for GappedRange { fn add_to_diag(self, diag: &mut Diag<'_, G>) { let GappedRange { span, gap, first_range } = self; - // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` - // does not support `#[subdiagnostic(eager)]`... + // FIXME(mejrs) Use `#[subdiagnostic(eager)]` instead let message = format!( "this could appear to continue range `{first_range}`, but `{gap}` isn't matched by \ either of them" diff --git a/tests/ui/lint/decorate-ice/decorate-def-path-str-ice.rs b/tests/ui/lint/decorate-ice/decorate-def-path-str-ice.rs index 8116e36ed0d9..3bb9882d348a 100644 --- a/tests/ui/lint/decorate-ice/decorate-def-path-str-ice.rs +++ b/tests/ui/lint/decorate-ice/decorate-def-path-str-ice.rs @@ -3,17 +3,16 @@ // Previously, this test ICEs when the `unused_must_use` lint is suppressed via the combination of // `-A warnings` and `--cap-lints=warn`, because: // -// - Its lint diagnostic struct `UnusedDef` implements `LintDiagnostic` manually and in the impl +// - Its lint diagnostic struct `UnusedDef` implements `Diagnostic` manually and in the impl // `def_path_str` was called (which calls `trimmed_def_path`, which will produce a // `must_produce_diag` ICE if a trimmed def path is constructed but never emitted in a diagnostic // because it is expensive to compute). -// - A `LintDiagnostic` has a `decorate_lint` method which decorates a `Diag` with lint-specific -// information. This method is wrapped by a `decorate` closure in `TyCtxt` diagnostic emission -// machinery, and the `decorate` closure called as late as possible. -// - `decorate`'s invocation is delayed as late as possible until `lint_level` is called. +// - A `Diagnostic` has an `into_diag` method which generates a `Diag` with (potentially) +// lint-specific information. +// - The `into_diag` method is called as late as possible until `diag_lint_level` is called. // - If a lint's corresponding diagnostic is suppressed (to be effectively allow at the final // emission time) via `-A warnings` or `--cap-lints=allow` (or `-A warnings` + `--cap-lints=warn` -// like in this test case), `decorate` is still called and a diagnostic is still constructed -- +// like in this test case), `into_diag` is still called and a diagnostic is still constructed -- // but the diagnostic is never eventually emitted, triggering the aforementioned // `must_produce_diag` ICE due to use of `trimmed_def_path`. // From 72de815eb2284b5eec85a56664fa08ba62d19f93 Mon Sep 17 00:00:00 2001 From: Mikkel Paulson Date: Fri, 27 Feb 2026 13:24:18 -0500 Subject: [PATCH 57/59] reference local MAIN_SEPARATOR_STR Change reference to imported MAIN_SEP_STR to local MAIN_SEPARATOR_STR, removing an unnecessary import. --- library/std/src/path.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9026606987e1..7887071d548e 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -93,7 +93,7 @@ use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; -use crate::sys::path::{HAS_PREFIXES, MAIN_SEP_STR, is_sep_byte, is_verbatim_sep, parse_prefix}; +use crate::sys::path::{HAS_PREFIXES, is_sep_byte, is_verbatim_sep, parse_prefix}; use crate::{cmp, fmt, fs, io, sys}; //////////////////////////////////////////////////////////////////////////////// @@ -562,7 +562,7 @@ impl<'a> Component<'a> { pub fn as_os_str(self) -> &'a OsStr { match self { Component::Prefix(p) => p.as_os_str(), - Component::RootDir => OsStr::new(MAIN_SEP_STR), + Component::RootDir => OsStr::new(MAIN_SEPARATOR_STR), Component::CurDir => OsStr::new("."), Component::ParentDir => OsStr::new(".."), Component::Normal(path) => path, @@ -1379,7 +1379,7 @@ fn _push(&mut self, path: &Path) { for c in buf { if need_sep && c != Component::RootDir { - res.push(MAIN_SEP_STR); + res.push(MAIN_SEPARATOR_STR); } res.push(c.as_os_str()); @@ -1402,7 +1402,7 @@ fn _push(&mut self, path: &Path) { // `path` is a pure relative path } else if need_sep { - self.inner.push(MAIN_SEP_STR); + self.inner.push(MAIN_SEPARATOR_STR); } self.inner.push(path); From d8092147fe8a61d8068da4be1109f221e8155fa3 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 4 Mar 2026 15:23:36 +0100 Subject: [PATCH 58/59] Rename translation -> formatting --- .../rustc_borrowck/src/diagnostics/mod.rs | 2 +- compiler/rustc_builtin_macros/src/errors.rs | 6 ++-- compiler/rustc_codegen_llvm/src/errors.rs | 2 +- compiler/rustc_const_eval/src/errors.rs | 12 +++---- .../src/interpret/eval_context.rs | 2 +- .../src/annotate_snippet_emitter_writer.rs | 2 +- compiler/rustc_errors/src/diagnostic.rs | 8 ++--- compiler/rustc_errors/src/emitter.rs | 2 +- .../src/{translation.rs => formatting.rs} | 14 +++----- compiler/rustc_errors/src/json.rs | 14 ++++---- compiler/rustc_errors/src/lib.rs | 34 +++++++++---------- compiler/rustc_hir_typeck/src/errors.rs | 6 ++-- compiler/rustc_lint/src/if_let_rescope.rs | 2 +- compiler/rustc_lint/src/lints.rs | 2 +- .../src/diagnostics/subdiagnostic.rs | 2 +- .../src/lint_tail_expr_drop_order.rs | 4 +-- compiler/rustc_resolve/src/errors.rs | 2 +- compiler/rustc_trait_selection/src/errors.rs | 18 +++++----- .../src/errors/note_and_explain.rs | 2 +- .../passes/lint/check_code_block_syntax.rs | 2 +- triagebot.toml | 6 ++-- 21 files changed, 68 insertions(+), 76 deletions(-) rename compiler/rustc_errors/src/{translation.rs => formatting.rs} (79%) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index ade3d928a022..28be1a9fdf8e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1310,7 +1310,7 @@ fn explain_captures( { let mut span: MultiSpan = spans.clone().into(); err.arg("ty", param_ty.to_string()); - let msg = err.dcx.eagerly_translate_to_string( + let msg = err.dcx.eagerly_format_to_string( msg!("`{$ty}` is made to be an `FnOnce` closure here"), err.args.iter(), ); diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index f8b466373e0b..961644b97759 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -764,7 +764,7 @@ pub(crate) struct FormatUnusedArg { impl Subdiagnostic for FormatUnusedArg { fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("named", self.named); - let msg = diag.eagerly_translate(msg!( + let msg = diag.eagerly_format(msg!( "{$named -> [true] named argument *[false] argument @@ -947,8 +947,8 @@ pub(crate) struct AsmClobberNoReg { impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { // eager translation as `span_labels` takes `AsRef` - let lbl1 = dcx.eagerly_translate_to_string(msg!("clobber_abi"), [].into_iter()); - let lbl2 = dcx.eagerly_translate_to_string(msg!("generic outputs"), [].into_iter()); + let lbl1 = dcx.eagerly_format_to_string(msg!("clobber_abi"), [].into_iter()); + let lbl2 = dcx.eagerly_format_to_string(msg!("generic outputs"), [].into_iter()); Diag::new( dcx, level, diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index af154a1aea80..89bfdfbd9e57 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -24,7 +24,7 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let diag: Diag<'_, G> = self.0.into_diag(dcx, level); let (message, _) = diag.messages.first().expect("`LlvmError` with no message"); - let message = dcx.eagerly_translate_to_string(message.clone(), diag.args.iter()); + let message = dcx.eagerly_format_to_string(message.clone(), diag.args.iter()); Diag::new( dcx, level, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index cdc02ae6933d..4797b039c962 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -366,7 +366,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { if self.has_label && !self.span.is_dummy() { span.push_span_label(self.span, msg!("the failure occurred here")); } - let msg = diag.eagerly_translate(msg!( + let msg = diag.eagerly_format(msg!( r#"{$times -> [0] inside {$where_ -> [closure] closure @@ -624,7 +624,7 @@ fn debug(self) -> String let mut diag = dcx.struct_allow(DiagMessage::Str(String::new().into())); let message = self.diagnostic_message(); self.add_args(&mut diag); - let s = dcx.eagerly_translate_to_string(message, diag.args.iter()); + let s = dcx.eagerly_format_to_string(message, diag.args.iter()); diag.cancel(); s }) @@ -1086,12 +1086,12 @@ fn add_args(self, err: &mut Diag<'_, G>) { } let message = if let Some(path) = self.path { - err.dcx.eagerly_translate_to_string( + err.dcx.eagerly_format_to_string( msg!("constructing invalid value at {$path}"), [("path".into(), DiagArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)), ) } else { - err.dcx.eagerly_translate_to_string(msg!("constructing invalid value"), [].into_iter()) + err.dcx.eagerly_format_to_string(msg!("constructing invalid value"), [].into_iter()) }; err.arg("front_matter", message); @@ -1122,7 +1122,7 @@ fn add_range_arg( ("hi".into(), DiagArgValue::Str(hi.to_string().into())), ]; let args = args.iter().map(|(a, b)| (a, b)); - let message = err.dcx.eagerly_translate_to_string(msg, args); + let message = err.dcx.eagerly_format_to_string(msg, args); err.arg("in_range", message); } @@ -1144,7 +1144,7 @@ fn add_range_arg( ExpectedKind::EnumTag => msg!("expected a valid enum tag"), ExpectedKind::Str => msg!("expected a string"), }; - let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter()); + let msg = err.dcx.eagerly_format_to_string(msg, [].into_iter()); err.arg("expected", msg); } InvalidEnumTag { value } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3a887f8afaa5..5ab69b9cb462 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -235,7 +235,7 @@ pub fn format_interp_error<'tcx>(dcx: DiagCtxtHandle<'_>, e: InterpErrorInfo<'tc let mut diag = dcx.struct_allow(""); let msg = e.diagnostic_message(); e.add_args(&mut diag); - let s = dcx.eagerly_translate_to_string(msg, diag.args.iter()); + let s = dcx.eagerly_format_to_string(msg, diag.args.iter()); diag.cancel(); s } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index 145937b22bea..c3c9f26c3157 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -26,7 +26,7 @@ ConfusionType, Destination, MAX_SUGGESTIONS, OutputTheme, detect_confusion_type, is_different, normalize_whitespace, should_show_source_code, }; -use crate::translation::{format_diag_message, format_diag_messages}; +use crate::formatting::{format_diag_message, format_diag_messages}; use crate::{ CodeSuggestion, DiagInner, DiagMessage, Emitter, ErrCode, Level, MultiSpan, Style, Subdiag, SuggestionStyle, TerminalUrl, diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 888009bf9d4c..0797ef3ec0d2 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1143,7 +1143,7 @@ pub fn tool_only_span_suggestion( } } /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see - /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages + /// [rustc_macros::Subdiagnostic]). Performs eager formatting of any messages /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of /// interpolated variables). pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self { @@ -1153,12 +1153,12 @@ pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self /// Fluent variables are not namespaced from each other, so when /// `Diagnostic`s and `Subdiagnostic`s use the same variable name, - /// one value will clobber the other. Eagerly translating the + /// one value will clobber the other. Eagerly formatting the /// diagnostic uses the variables defined right then, before the /// clobbering occurs. - pub fn eagerly_translate(&self, msg: impl Into) -> DiagMessage { + pub fn eagerly_format(&self, msg: impl Into) -> DiagMessage { let args = self.args.iter(); - self.dcx.eagerly_translate(msg.into(), args) + self.dcx.eagerly_format(msg.into(), args) } with_fn! { with_span, diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 8bb7dc35d82d..fa3ff21b2726 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -23,8 +23,8 @@ use rustc_span::{FileName, SourceFile, Span}; use tracing::{debug, warn}; +use crate::formatting::format_diag_message; use crate::timings::TimingRecord; -use crate::translation::format_diag_message; use crate::{ CodeSuggestion, DiagInner, DiagMessage, Level, MultiSpan, Style, Subdiag, SuggestionStyle, }; diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/formatting.rs similarity index 79% rename from compiler/rustc_errors/src/translation.rs rename to compiler/rustc_errors/src/formatting.rs index 0de40cd84dcf..1e0d9b7f5f92 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/formatting.rs @@ -8,10 +8,7 @@ use crate::{DiagArg, DiagMessage, Style, fluent_bundle}; /// Convert diagnostic arguments (a rustc internal type that exists to implement -/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. -/// -/// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then -/// passed around as a reference thereafter. +/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform formatting. fn to_fluent_args<'iter>(iter: impl Iterator>) -> FluentArgs<'static> { let mut args = if let Some(size) = iter.size_hint().1 { FluentArgs::with_capacity(size) @@ -40,9 +37,6 @@ pub fn format_diag_message<'a>(message: &'a DiagMessage, args: &DiagArgMap) -> C match message { DiagMessage::Str(msg) => Cow::Borrowed(msg), - // This translates an inline fluent diagnostic message - // It does this by creating a new `FluentBundle` with only one message, - // and then translating using this bundle. DiagMessage::Inline(msg) => { const GENERATED_MSG_ID: &str = "generated_msg"; let resource = @@ -56,10 +50,10 @@ pub fn format_diag_message<'a>(message: &'a DiagMessage, args: &DiagArgMap) -> C let args = to_fluent_args(args.iter()); let mut errs = vec![]; - let translated = bundle.format_pattern(value, Some(&args), &mut errs).to_string(); - debug!(?translated, ?errs); + let formatted = bundle.format_pattern(value, Some(&args), &mut errs).to_string(); + debug!(?formatted, ?errs); if errs.is_empty() { - Cow::Owned(translated) + Cow::Owned(formatted) } else { panic!("Fluent errors while formatting message: {errs:?}"); } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 3b266d058b14..04ac140f3326 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -30,8 +30,8 @@ ColorConfig, Destination, Emitter, HumanReadableErrorType, OutputTheme, TimingEvent, should_show_source_code, }; +use crate::formatting::{format_diag_message, format_diag_messages}; use crate::timings::{TimingRecord, TimingSection}; -use crate::translation::{format_diag_message, format_diag_messages}; use crate::{CodeSuggestion, MultiSpan, SpanLabel, Subdiag, Suggestions, TerminalUrl}; #[cfg(test)] @@ -299,9 +299,9 @@ impl Diagnostic { /// Converts from `rustc_errors::DiagInner` to `Diagnostic`. fn from_errors_diagnostic(diag: crate::DiagInner, je: &JsonEmitter) -> Diagnostic { let sugg_to_diag = |sugg: &CodeSuggestion| { - let translated_message = format_diag_message(&sugg.msg, &diag.args); + let formatted_message = format_diag_message(&sugg.msg, &diag.args); Diagnostic { - message: translated_message.to_string(), + message: formatted_message.to_string(), code: None, level: "help", spans: DiagnosticSpan::from_suggestion(sugg, &diag.args, je), @@ -330,7 +330,7 @@ fn flush(&mut self) -> io::Result<()> { } } - let translated_message = format_diag_messages(&diag.messages, &diag.args); + let formatted_message = format_diag_messages(&diag.messages, &diag.args); let code = if let Some(code) = diag.code { Some(DiagnosticCode { @@ -380,7 +380,7 @@ fn flush(&mut self) -> io::Result<()> { let buf = String::from_utf8(buf).unwrap(); Diagnostic { - message: translated_message.to_string(), + message: formatted_message.to_string(), code, level, spans, @@ -390,9 +390,9 @@ fn flush(&mut self) -> io::Result<()> { } fn from_sub_diagnostic(subdiag: &Subdiag, args: &DiagArgMap, je: &JsonEmitter) -> Diagnostic { - let translated_message = format_diag_messages(&subdiag.messages, args); + let formatted_message = format_diag_messages(&subdiag.messages, args); Diagnostic { - message: translated_message.to_string(), + message: formatted_message.to_string(), code: None, level: subdiag.level.to_str(), spans: DiagnosticSpan::from_multispan(&subdiag.span, args, je), diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4ef4d5807463..36494ab1a1f8 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -68,8 +68,8 @@ use tracing::debug; use crate::emitter::TimingEvent; +use crate::formatting::format_diag_message; use crate::timings::TimingRecord; -use crate::translation::format_diag_message; pub mod annotate_snippet_emitter_writer; pub mod codes; @@ -77,11 +77,11 @@ mod diagnostic; mod diagnostic_impls; pub mod emitter; +pub mod formatting; pub mod json; mod lock; pub mod markdown; pub mod timings; -pub mod translation; pub type PResult<'a, T> = Result>; @@ -484,24 +484,24 @@ pub fn set_emitter(&self, emitter: Box) { self.inner.borrow_mut().emitter = emitter; } - /// Translate `message` eagerly with `args` to `DiagMessage::Eager`. - pub fn eagerly_translate<'a>( + /// Format `message` eagerly with `args` to `DiagMessage::Eager`. + pub fn eagerly_format<'a>( &self, message: DiagMessage, args: impl Iterator>, ) -> DiagMessage { let inner = self.inner.borrow(); - inner.eagerly_translate(message, args) + inner.eagerly_format(message, args) } - /// Translate `message` eagerly with `args` to `String`. - pub fn eagerly_translate_to_string<'a>( + /// Format `message` eagerly with `args` to `String`. + pub fn eagerly_format_to_string<'a>( &self, message: DiagMessage, args: impl Iterator>, ) -> String { let inner = self.inner.borrow(); - inner.eagerly_translate_to_string(message, args) + inner.eagerly_format_to_string(message, args) } // This is here to not allow mutation of flags; @@ -1419,17 +1419,17 @@ fn has_errors_or_delayed_bugs(&self) -> Option { self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied()) } - /// Translate `message` eagerly with `args` to `DiagMessage::Eager`. - fn eagerly_translate<'a>( + /// Format `message` eagerly with `args` to `DiagMessage::Eager`. + fn eagerly_format<'a>( &self, message: DiagMessage, args: impl Iterator>, ) -> DiagMessage { - DiagMessage::Str(Cow::from(self.eagerly_translate_to_string(message, args))) + DiagMessage::Str(Cow::from(self.eagerly_format_to_string(message, args))) } - /// Translate `message` eagerly with `args` to `String`. - fn eagerly_translate_to_string<'a>( + /// Format `message` eagerly with `args` to `String`. + fn eagerly_format_to_string<'a>( &self, message: DiagMessage, args: impl Iterator>, @@ -1438,12 +1438,12 @@ fn eagerly_translate_to_string<'a>( format_diag_message(&message, &args).to_string() } - fn eagerly_translate_for_subdiag( + fn eagerly_format_for_subdiag( &self, diag: &DiagInner, msg: impl Into, ) -> DiagMessage { - self.eagerly_translate(msg.into(), diag.args.iter()) + self.eagerly_format(msg.into(), diag.args.iter()) } fn flush_delayed(&mut self) { @@ -1509,7 +1509,7 @@ fn flush_delayed(&mut self) { let msg = msg!( "`flushed_delayed` got diagnostic with level {$level}, instead of the expected `DelayedBug`" ); - let msg = self.eagerly_translate_for_subdiag(&bug, msg); // after the `arg` call + let msg = self.eagerly_format_for_subdiag(&bug, msg); // after the `arg` call bug.sub(Note, msg, bug.span.primary_span().unwrap().into()); } bug.level = Bug; @@ -1560,7 +1560,7 @@ fn decorate(self, dcx: &DiagCtxtInner) -> DiagInner { }; diag.arg("emitted_at", diag.emitted_at.clone()); diag.arg("note", self.note); - let msg = dcx.eagerly_translate_for_subdiag(&diag, msg); // after the `arg` calls + let msg = dcx.eagerly_format_for_subdiag(&diag, msg); // after the `arg` calls diag.sub(Note, msg, diag.span.primary_span().unwrap_or(DUMMY_SP).into()); diag } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 0f33cf0b8433..52f6b126a7d0 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -987,13 +987,13 @@ impl rustc_errors::Subdiagnostic for CastUnknownPointerSub { fn add_to_diag(self, diag: &mut Diag<'_, G>) { match self { CastUnknownPointerSub::To(span) => { - let msg = diag.eagerly_translate(msg!("needs more type information")); + let msg = diag.eagerly_format(msg!("needs more type information")); diag.span_label(span, msg); - let msg = diag.eagerly_translate(msg!("the type information given here is insufficient to check whether the pointer cast is valid")); + let msg = diag.eagerly_format(msg!("the type information given here is insufficient to check whether the pointer cast is valid")); diag.note(msg); } CastUnknownPointerSub::From(span) => { - let msg = diag.eagerly_translate(msg!("the type information given here is insufficient to check whether the pointer cast is valid")); + let msg = diag.eagerly_format(msg!("the type information given here is insufficient to check whether the pointer cast is valid")); diag.span_label(span, msg); } } diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index ba196ef301c0..0a754a7af03b 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -354,7 +354,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { .chain(repeat_n('}', closing_brackets.count)) .collect(), )); - let msg = diag.eagerly_translate(msg!( + let msg = diag.eagerly_format(msg!( "a `match` with a single arm can preserve the drop order up to Edition 2021" )); diag.multipart_suggestion_with_style( diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 40021debca0b..5597c5b4c839 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3629,7 +3629,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { Explicit { lifetime_name, suggestions, optional_alternative } => { diag.arg("lifetime_name", lifetime_name); - let msg = diag.eagerly_translate(msg!("consistently use `{$lifetime_name}`")); + let msg = diag.eagerly_format(msg!("consistently use `{$lifetime_name}`")); diag.remove_arg("lifetime_name"); diag.multipart_suggestion_with_style( msg, diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 5907e268e91b..623742132208 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -536,7 +536,7 @@ pub(crate) fn into_tokens(&mut self) -> Result(self, diag: &mut rustc_errors diag.arg("is_generated_name", self.is_generated_name); diag.remove_arg("is_dropped_first_edition_2024"); diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024); - let msg = diag.eagerly_translate(msg!( + let msg = diag.eagerly_format(msg!( "{$is_generated_name -> [true] this value will be stored in a temporary; let us call it `{$name}` *[false] `{$name}` calls a custom destructor @@ -542,7 +542,7 @@ fn add_to_diag(self, diag: &mut rustc_errors dtor.add_to_diag(diag); } let msg = - diag.eagerly_translate(msg!( + diag.eagerly_format(msg!( "{$is_dropped_first_edition_2024 -> [true] up until Edition 2021 `{$name}` is dropped last but will be dropped earlier in Edition 2024 *[false] `{$name}` will be dropped later as of Edition 2024 diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 2a0021ebc3bd..54427535c5f6 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1366,7 +1366,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { ItemWas::BehindFeature { feature, span } => { let key = "feature".into(); let value = feature.into_diag_arg(&mut None); - let msg = diag.dcx.eagerly_translate_to_string( + let msg = diag.dcx.eagerly_format_to_string( msg!("the item is gated behind the `{$feature}` feature"), [(&key, &value)].into_iter(), ); diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 03d24ebc20d3..254a626ce221 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -456,7 +456,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { // See https://github.com/rust-lang/rust/issues/143872 for details. diag.store_args(); diag.arg("requirement", requirement); - let msg = diag.eagerly_translate(msg!( + let msg = diag.eagerly_format(msg!( "...so that the {$requirement -> [method_compat] method type is compatible with trait [type_compat] associated type is compatible with trait @@ -482,7 +482,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { // *terrible*. diag.store_args(); diag.arg("requirement", requirement); - let msg = diag.eagerly_translate(msg!( + let msg = diag.eagerly_format(msg!( "...so that {$requirement -> [method_compat] method type is compatible with trait [type_compat] associated type is compatible with trait @@ -1174,7 +1174,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { type_param_span .push_span_label(span, msg!("consider borrowing this type parameter in the trait")); } - let msg = diag.eagerly_translate(msg!("the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`")); + let msg = diag.eagerly_format(msg!("the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`")); diag.span_help(type_param_span, msg); } } @@ -1218,10 +1218,9 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { self.ident.span, msg!("calling this method introduces the `impl`'s `'static` requirement"), ); - let msg = diag.eagerly_translate(msg!("the used `impl` has a `'static` requirement")); + let msg = diag.eagerly_format(msg!("the used `impl` has a `'static` requirement")); diag.span_note(multi_span, msg); - let msg = - diag.eagerly_translate(msg!("consider relaxing the implicit `'static` requirement")); + let msg = diag.eagerly_format(msg!("consider relaxing the implicit `'static` requirement")); diag.span_suggestion_verbose( self.span.shrink_to_hi(), msg, @@ -1284,9 +1283,8 @@ fn add_to_diag(mut self, diag: &mut Diag<'_, G>) { ); } self.span.push_span_label(self.cause_span, msg!("because of this returned expression")); - let msg = diag.eagerly_translate(msg!( - "\"`'static` lifetime requirement introduced by the return type" - )); + let msg = diag + .eagerly_format(msg!("\"`'static` lifetime requirement introduced by the return type")); diag.span_note(self.span, msg); } } @@ -1727,7 +1725,7 @@ impl Subdiagnostic for SuggestTuplePatternMany { fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("path", self.path); let message = - diag.eagerly_translate(msg!("try wrapping the pattern in a variant of `{$path}`")); + diag.eagerly_format(msg!("try wrapping the pattern in a variant of `{$path}`")); diag.multipart_suggestions( message, self.compatible_variants.into_iter().map(|variant| { diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 08618be03e75..5121ca886c1b 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -169,7 +169,7 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); - let msg = diag.eagerly_translate(msg!( + let msg = diag.eagerly_format(msg!( "{$pref_kind -> *[should_not_happen] [{$pref_kind}] [ref_valid_for] ...the reference is valid for diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index be1168b2ecee..e94fd996947b 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -5,7 +5,7 @@ use rustc_data_structures::sync::Lock; use rustc_errors::emitter::Emitter; -use rustc_errors::translation::format_diag_message; +use rustc_errors::formatting::format_diag_message; use rustc_errors::{Applicability, DiagCtxt, DiagInner}; use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal}; use rustc_resolve::rustdoc::source_span_for_markdown_range; diff --git a/triagebot.toml b/triagebot.toml index b1675e00f0df..0bcddeb144ad 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -534,7 +534,7 @@ trigger_files = [ [autolabel."A-translation"] trigger_files = [ "compiler/rustc_error_messages", - "compiler/rustc_errors/src/translation.rs", + "compiler/rustc_errors/src/formatting.rs", "compiler/rustc_macros/src/diagnostics" ] @@ -1180,8 +1180,8 @@ cc = ["@Muscraft"] message = "`rustc_errors::emitter` was changed" cc = ["@Muscraft"] -[mentions."compiler/rustc_errors/src/translation.rs"] -message = "`rustc_errors::translation` was changed" +[mentions."compiler/rustc_errors/src/formatting.rs"] +message = "`rustc_errors::formatting` was changed" cc = ["@davidtwco", "@TaKO8Ki", "@JonathanBrouwer"] [mentions."compiler/rustc_macros/src/diagnostics"] From 098b1b98f5ebb4e8790c663f27746e9d323cc63c Mon Sep 17 00:00:00 2001 From: Mikkel Paulson Date: Fri, 27 Feb 2026 13:22:37 -0500 Subject: [PATCH 59/59] make path separators available in const context * consolidate various representations of separators in std::sys::path into a single macro_rules invocation per platform to save transcription errors * make `std::path::is_separator()` const * new constants `std::path::{SEPARATORS, SEPARATORS_STR}` --- library/std/src/path.rs | 29 +++++++++++++------ library/std/src/sys/path/cygwin.rs | 11 ++----- library/std/src/sys/path/mod.rs | 19 ++++++++++++ library/std/src/sys/path/sgx.rs | 11 ++----- library/std/src/sys/path/uefi.rs | 13 +++------ library/std/src/sys/path/unix.rs | 11 ++----- .../std/src/sys/path/unsupported_backslash.rs | 11 ++----- library/std/src/sys/path/windows.rs | 11 ++----- 8 files changed, 58 insertions(+), 58 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7887071d548e..0b2b5f7e58f4 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -266,22 +266,33 @@ fn has_implicit_root(&self) -> bool { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -pub fn is_separator(c: char) -> bool { +#[rustc_const_unstable(feature = "const_path_separators", issue = "153106")] +pub const fn is_separator(c: char) -> bool { c.is_ascii() && is_sep_byte(c as u8) } -/// The primary separator of path components for the current platform. -/// -/// For example, `/` on Unix and `\` on Windows. +/// All path separators recognized on the current platform, represented as [`char`]s; for example, +/// this is `&['/'][..]` on Unix and `&['\\', '/'][..]` on Windows. The [primary +/// separator](MAIN_SEPARATOR) is always element 0 of the slice. +#[unstable(feature = "const_path_separators", issue = "153106")] +pub const SEPARATORS: &[char] = crate::sys::path::SEPARATORS; + +/// All path separators recognized on the current platform, represented as [`&str`]s; for example, +/// this is `&["/"][..]` on Unix and `&["\\", "/"][..]` on Windows. The [primary +/// separator](MAIN_SEPARATOR_STR) is always element 0 of the slice. +#[unstable(feature = "const_path_separators", issue = "153106")] +pub const SEPARATORS_STR: &[&str] = crate::sys::path::SEPARATORS_STR; + +/// The primary separator of path components for the current platform, represented as a [`char`]; +/// for example, this is `'/'` on Unix and `'\\'` on Windows. #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "path_main_separator")] -pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP; +pub const MAIN_SEPARATOR: char = SEPARATORS[0]; -/// The primary separator of path components for the current platform. -/// -/// For example, `/` on Unix and `\` on Windows. +/// The primary separator of path components for the current platform, represented as a [`&str`]; +/// for example, this is `"/"` on Unix and `"\\"` on Windows. #[stable(feature = "main_separator_str", since = "1.68.0")] -pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR; +pub const MAIN_SEPARATOR_STR: &str = SEPARATORS_STR[0]; //////////////////////////////////////////////////////////////////////////////// // Misc helpers diff --git a/library/std/src/sys/path/cygwin.rs b/library/std/src/sys/path/cygwin.rs index 75f0de6beaeb..494dd91f2314 100644 --- a/library/std/src/sys/path/cygwin.rs +++ b/library/std/src/sys/path/cygwin.rs @@ -5,25 +5,20 @@ use crate::sys::helpers::run_path_with_cstr; use crate::{io, ptr}; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' -} +path_separator_bytes!(b'/', b'\\'); /// Cygwin always prefers `/` over `\`, and it always converts all `/` to `\` /// internally when calling Win32 APIs. Therefore, the server component of path /// `\\?\UNC\localhost/share` is `localhost/share` on Win32, but `localhost` /// on Cygwin. #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' || b == b'\\' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub use super::windows_prefix::parse_prefix; pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; unsafe extern "C" { // Doc: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs index 254683bc83f9..bbb7577e186a 100644 --- a/library/std/src/sys/path/mod.rs +++ b/library/std/src/sys/path/mod.rs @@ -1,3 +1,22 @@ +// There's a lot of necessary redundancy in separator definition. Consolidated into a macro to +// prevent transcription errors. +macro_rules! path_separator_bytes { + ($($sep:literal),+) => ( + pub const SEPARATORS: &[char] = &[$($sep as char,)+]; + pub const SEPARATORS_STR: &[&str] = &[$( + match str::from_utf8(&[$sep]) { + Ok(s) => s, + Err(_) => panic!("path_separator_bytes must be ASCII bytes"), + } + ),+]; + + #[inline] + pub const fn is_sep_byte(b: u8) -> bool { + $(b == $sep) ||+ + } + ) +} + cfg_select! { target_os = "windows" => { mod windows; diff --git a/library/std/src/sys/path/sgx.rs b/library/std/src/sys/path/sgx.rs index dca61f3ea145..9b7ab30a9c65 100644 --- a/library/std/src/sys/path/sgx.rs +++ b/library/std/src/sys/path/sgx.rs @@ -3,14 +3,11 @@ use crate::path::{Path, PathBuf, Prefix}; use crate::sys::unsupported; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} +path_separator_bytes!(b'/'); #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub fn parse_prefix(_: &OsStr) -> Option> { @@ -18,8 +15,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = false; -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; pub(crate) fn absolute(_path: &Path) -> io::Result { unsupported() diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs index 84d634af93cf..8c911ee5f9c5 100644 --- a/library/std/src/sys/path/uefi.rs +++ b/library/std/src/sys/path/uefi.rs @@ -5,17 +5,14 @@ use crate::sys::pal::helpers; use crate::sys::unsupported_err; +path_separator_bytes!(b'\\'); + const FORWARD_SLASH: u8 = b'/'; const COLON: u8 = b':'; #[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'\\' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub fn parse_prefix(_: &OsStr) -> Option> { @@ -23,8 +20,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; /// UEFI paths can be of 4 types: /// diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs index 611d250db405..b49c39a9253f 100644 --- a/library/std/src/sys/path/unix.rs +++ b/library/std/src/sys/path/unix.rs @@ -2,14 +2,11 @@ use crate::path::{Path, PathBuf, Prefix}; use crate::{env, io}; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} +path_separator_bytes!(b'/'); #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } #[inline] @@ -18,8 +15,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = false; -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; /// Make a POSIX path absolute without changing its semantics. pub(crate) fn absolute(path: &Path) -> io::Result { diff --git a/library/std/src/sys/path/unsupported_backslash.rs b/library/std/src/sys/path/unsupported_backslash.rs index 8ed1fdc36e23..ce1851e93839 100644 --- a/library/std/src/sys/path/unsupported_backslash.rs +++ b/library/std/src/sys/path/unsupported_backslash.rs @@ -4,14 +4,11 @@ use crate::path::{Path, PathBuf, Prefix}; use crate::sys::unsupported; -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'\\' -} +path_separator_bytes!(b'\\'); #[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' +pub const fn is_verbatim_sep(b: u8) -> bool { + is_sep_byte(b) } pub fn parse_prefix(_: &OsStr) -> Option> { @@ -19,8 +16,6 @@ pub fn parse_prefix(_: &OsStr) -> Option> { } pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; pub(crate) fn absolute(_path: &Path) -> io::Result { unsupported() diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs index 509b13b6ae81..1c7bf50d1907 100644 --- a/library/std/src/sys/path/windows.rs +++ b/library/std/src/sys/path/windows.rs @@ -9,9 +9,9 @@ pub use super::windows_prefix::parse_prefix; +path_separator_bytes!(b'\\', b'/'); + pub const HAS_PREFIXES: bool = true; -pub const MAIN_SEP_STR: &str = "\\"; -pub const MAIN_SEP: char = '\\'; /// A null terminated wide string. #[repr(transparent)] @@ -48,12 +48,7 @@ pub fn with_native_path(path: &Path, f: &dyn Fn(&WCStr) -> io::Result) -> } #[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { +pub const fn is_verbatim_sep(b: u8) -> bool { b == b'\\' }