From 384f363b7023244df33bef7eb8070a334eae9b48 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 13 Mar 2026 14:32:54 -0400 Subject: [PATCH 01/15] change "error finalizing incremental compilation" from warning to note The warning has no error code, so in a `-D warnings` environment, it's impossible to ignore if it consistently breaks your build. Change it to a note so it is still visible, but doesn't break the build --- compiler/rustc_incremental/src/persist/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index f73cc4d43e8c5..cf80a7ac2c469 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -366,7 +366,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) { } Err(e) => { // Warn about the error. However, no need to abort compilation now. - sess.dcx().emit_warn(errors::Finalize { path: &incr_comp_session_dir, err: e }); + sess.dcx().emit_note(errors::Finalize { path: &incr_comp_session_dir, err: e }); debug!("finalize_session_directory() - error, marking as invalid"); // Drop the file lock, so we can garage collect From 4845f7842228c03910b3bf5d1a4221eea4e14f5d Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Tue, 17 Mar 2026 15:59:08 -0400 Subject: [PATCH 02/15] Reword the incremental finalize diagnostic Remove the confusing word "error". The diagnostic is already prefixed with a level when it is displayed, so this is redundant and possibly confusing ("warning: error ..."). Add some help text summarizing the impact of what happened: the next build won't be able to reuse work from the current run. --- compiler/rustc_incremental/src/errors.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs index 3354689d0ca33..a1f4464c76592 100644 --- a/compiler/rustc_incremental/src/errors.rs +++ b/compiler/rustc_incremental/src/errors.rs @@ -192,7 +192,8 @@ pub(crate) struct DeleteFull<'a> { } #[derive(Diagnostic)] -#[diag("error finalizing incremental compilation session directory `{$path}`: {$err}")] +#[diag("did not finalize incremental compilation session directory `{$path}`: {$err}")] +#[help("the next build will not be able to reuse work from this compilation")] pub(crate) struct Finalize<'a> { pub path: &'a Path, pub err: std::io::Error, From 2c52bc599e666e3631db2cd48fc7886ec70fe5c7 Mon Sep 17 00:00:00 2001 From: aisr Date: Thu, 19 Mar 2026 15:01:48 +0800 Subject: [PATCH 03/15] format safety doc of Rc/Arc::from_raw/from_raw_in --- library/alloc/src/rc.rs | 56 ++++++++++++++++++++++----------------- library/alloc/src/sync.rs | 54 ++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 49 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 8a651618ca83e..1f29b3b47d2e8 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1430,29 +1430,32 @@ impl Rc { /// Constructs an `Rc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to - /// [`Rc::into_raw`][into_raw] with the following requirements: + /// [`Rc::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator]. /// + /// # Safety + /// + /// * Creating a `Rc` from a pointer other than one returned from + /// [`Rc::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and /// alignment as `T`. This is trivially true if `Rc` was constructed /// through `Rc` and then converted to `Rc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by the global allocator - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by the global allocator + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw + /// [into_raw_with_allocator]: Rc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// @@ -1662,29 +1665,32 @@ impl Rc { /// Constructs an `Rc` from a raw pointer in the provided allocator. /// /// The raw pointer must have been previously returned by a call to [`Rc::into_raw`][into_raw] with the following requirements: + /// A>::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator]. + /// + /// # Safety /// + /// * Creating a `Rc` from a pointer other than one returned from + /// [`Rc::into_raw`][into_raw] or [`Rc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Rc` was constructed - /// through `Rc` and then converted to `Rc` through an [unsized + /// alignment as `T`. This is trivially true if `Rc` was constructed + /// through `Rc` and then converted to `Rc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by `alloc` - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by `alloc` + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, - /// even if the returned `Rc` is never accessed. + /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw + /// [into_raw_with_allocator]: Rc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 2c9fadbb8d9ef..368afb9011f9f 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1581,29 +1581,32 @@ impl Arc { /// Constructs an `Arc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to - /// [`Arc::into_raw`][into_raw] with the following requirements: + /// [`Arc::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator]. /// + /// # Safety + /// + /// * Creating a `Arc` from a pointer other than one returned from + /// [`Arc::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and /// alignment as `T`. This is trivially true if `Arc` was constructed /// through `Arc` and then converted to `Arc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by the global allocator. - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by the global allocator. + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Arc` is never accessed. /// /// [into_raw]: Arc::into_raw + /// [into_raw_with_allocator]: Arc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// @@ -1819,29 +1822,32 @@ impl Arc { /// Constructs an `Arc` from a raw pointer. /// /// The raw pointer must have been previously returned by a call to [`Arc::into_raw`][into_raw] with the following requirements: + /// A>::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator]. + /// + /// # Safety /// + /// * Creating a `Arc` from a pointer other than one returned from + /// [`Arc::into_raw`][into_raw] or [`Arc::into_raw_with_allocator`][into_raw_with_allocator] + /// is undefined behavior. /// * If `U` is sized, it must have the same size and alignment as `T`. This /// is trivially true if `U` is `T`. /// * If `U` is unsized, its data pointer must have the same size and - /// alignment as `T`. This is trivially true if `Arc` was constructed - /// through `Arc` and then converted to `Arc` through an [unsized + /// alignment as `T`. This is trivially true if `Arc` was constructed + /// through `Arc` and then converted to `Arc` through an [unsized /// coercion]. - /// - /// Note that if `U` or `U`'s data pointer is not `T` but has the same size - /// and alignment, this is basically like transmuting references of - /// different types. See [`mem::transmute`][transmute] for more information - /// on what restrictions apply in this case. - /// - /// The raw pointer must point to a block of memory allocated by `alloc` - /// - /// The user of `from_raw` has to make sure a specific value of `T` is only - /// dropped once. + /// * Note that if `U` or `U`'s data pointer is not `T` but has the same size + /// and alignment, this is basically like transmuting references of + /// different types. See [`mem::transmute`][transmute] for more information + /// on what restrictions apply in this case. + /// * The raw pointer must point to a block of memory allocated by `alloc` + /// * The user of `from_raw` has to make sure a specific value of `T` is only + /// dropped once. /// /// This function is unsafe because improper use may lead to memory unsafety, /// even if the returned `Arc` is never accessed. /// /// [into_raw]: Arc::into_raw + /// [into_raw_with_allocator]: Arc::into_raw_with_allocator /// [transmute]: core::mem::transmute /// [unsized coercion]: https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions /// From 0cc494621967992bd1f72415ab244832ef55a1f5 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 19 Mar 2026 21:18:31 -0400 Subject: [PATCH 04/15] add a test to make rustc_incremental finalize_session_directory rename fail Use a proc macro to observe the incremental session directory and do something platform specific so that renaming the '-working' session directory during finalize_session_directory will fail. On Unix, change the permissions on the parent directory to be read-only. On Windows, open and leak a file inside the `-working` directory. --- .../run-make/incremental-finalize-fail/foo.rs | 5 + .../incremental-finalize-fail/poison/lib.rs | 87 +++++++++++++++ .../incremental-finalize-fail/rmake.rs | 103 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 tests/run-make/incremental-finalize-fail/foo.rs create mode 100644 tests/run-make/incremental-finalize-fail/poison/lib.rs create mode 100644 tests/run-make/incremental-finalize-fail/rmake.rs diff --git a/tests/run-make/incremental-finalize-fail/foo.rs b/tests/run-make/incremental-finalize-fail/foo.rs new file mode 100644 index 0000000000000..1f1e2842b4658 --- /dev/null +++ b/tests/run-make/incremental-finalize-fail/foo.rs @@ -0,0 +1,5 @@ +poison::poison_finalize!(); + +pub fn hello() -> i32 { + 42 +} diff --git a/tests/run-make/incremental-finalize-fail/poison/lib.rs b/tests/run-make/incremental-finalize-fail/poison/lib.rs new file mode 100644 index 0000000000000..e191cf7ade4cd --- /dev/null +++ b/tests/run-make/incremental-finalize-fail/poison/lib.rs @@ -0,0 +1,87 @@ +//! A proc macro that sabotages the incremental compilation finalize step. +//! +//! When invoked, it locates the `-working` session directory inside the +//! incremental compilation directory (passed via POISON_INCR_DIR) and +//! makes it impossible to rename: +//! +//! - On Unix: removes write permission from the parent (crate) directory. +//! - On Windows: creates a file inside the -working directory and leaks +//! the file handle, preventing the directory from being renamed. + +extern crate proc_macro; + +use std::fs; +use std::path::PathBuf; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn poison_finalize(_input: TokenStream) -> TokenStream { + let incr_dir = std::env::var("POISON_INCR_DIR").expect("POISON_INCR_DIR must be set"); + + let crate_dir = find_crate_dir(&incr_dir); + let working_dir = find_working_dir(&crate_dir); + + #[cfg(unix)] + poison_unix(&crate_dir); + + #[cfg(windows)] + poison_windows(&working_dir); + + TokenStream::new() +} + +/// Remove write permission from the crate directory. +/// This causes rename() to fail with EACCES +#[cfg(unix)] +fn poison_unix(crate_dir: &PathBuf) { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs::metadata(crate_dir).unwrap().permissions(); + perms.set_mode(0o555); // r-xr-xr-x + fs::set_permissions(crate_dir, perms).unwrap(); +} + +/// Create a file inside the -working directory and leak the +/// handle. Windows prevents renaming a directory when any file inside it +/// has an open handle. The handle stays open until the rustc process exits. +#[cfg(windows)] +fn poison_windows(working_dir: &PathBuf) { + let poison_file = working_dir.join("_poison_handle"); + let f = fs::File::create(&poison_file).unwrap(); + // Leak the handle so it stays open for the lifetime of the rustc process. + std::mem::forget(f); +} + +/// Find the crate directory for `foo` inside the incremental compilation dir. +/// +/// The incremental directory layout is: +/// {incr_dir}/{crate_name}-{stable_crate_id}/ +fn find_crate_dir(incr_dir: &str) -> PathBuf { + let mut dirs = fs::read_dir(incr_dir).unwrap().filter_map(|e| { + let e = e.ok()?; + let name = e.file_name(); + let name = name.to_str()?; + if e.file_type().ok()?.is_dir() && name.starts_with("foo-") { Some(e.path()) } else { None } + }); + + let first = + dirs.next().unwrap_or_else(|| panic!("no foo-* crate directory found in {incr_dir}")); + assert!( + dirs.next().is_none(), + "expected exactly one foo-* crate directory in {incr_dir}, found multiple" + ); + first +} + +/// Find the session directory ending in "-working" inside the crate directory +fn find_working_dir(crate_dir: &PathBuf) -> PathBuf { + for entry in fs::read_dir(crate_dir).unwrap() { + let entry = entry.unwrap(); + let name = entry.file_name(); + let name = name.to_str().unwrap().to_string(); + if name.starts_with("s-") && name.ends_with("-working") { + return entry.path(); + } + } + panic!("no -working session directory found in {}", crate_dir.display()); +} diff --git a/tests/run-make/incremental-finalize-fail/rmake.rs b/tests/run-make/incremental-finalize-fail/rmake.rs new file mode 100644 index 0000000000000..36ba2a48ca46b --- /dev/null +++ b/tests/run-make/incremental-finalize-fail/rmake.rs @@ -0,0 +1,103 @@ +//! Test that a failure to finalize the incremental compilation session directory +//! (i.e., the rename from "-working" to the SVH-based name) results in a +//! note, not an ICE, and that the compilation output is still produced. +//! +//! Strategy: +//! 1. Build the `poison` proc-macro crate +//! 2. Compile foo.rs with incremental compilation +//! The proc macro runs mid-compilation (after prepare_session_directory +//! but before finalize_session_directory) and sabotages the rename: +//! - On Unix: removes write permission from the crate directory, +//! so rename() fails with EACCES. +//! - On Windows: creates and leaks an open file handle inside the +//! -working directory, so rename() fails with ERROR_ACCESS_DENIED. +//! 3. Assert that stderr contains the finalize failure messages + +use std::fs; +use std::path::{Path, PathBuf}; + +use run_make_support::rustc; + +/// Guard that restores permissions on the incremental directory on drop, +/// to ensure cleanup is possible +struct IncrDirCleanup; + +fn main() { + let _cleanup = IncrDirCleanup; + + // Build the poison proc-macro crate + rustc().input("poison/lib.rs").crate_name("poison").crate_type("proc-macro").run(); + + let poison_dylib = find_proc_macro_dylib("poison"); + + // Incremental compile with the poison macro active + let out = rustc() + .input("foo.rs") + .crate_type("rlib") + .incremental("incr") + .extern_("poison", &poison_dylib) + .env("POISON_INCR_DIR", "incr") + .run(); + + out.assert_stderr_contains("note: did not finalize incremental compilation session directory"); + out.assert_stderr_contains( + "help: the next build will not be able to reuse work from this compilation", + ); + out.assert_stderr_not_contains("internal compiler error"); +} + +impl Drop for IncrDirCleanup { + fn drop(&mut self) { + let incr = Path::new("incr"); + if !incr.exists() { + return; + } + + #[cfg(unix)] + restore_permissions(incr); + } +} + +/// Recursively restore write permissions so rm -rf works after the chmod trick +#[cfg(unix)] +fn restore_permissions(path: &Path) { + use std::os::unix::fs::PermissionsExt; + if let Ok(entries) = fs::read_dir(path) { + for entry in entries.filter_map(|e| e.ok()) { + if entry.file_type().map_or(false, |ft| ft.is_dir()) { + let mut perms = match fs::metadata(entry.path()) { + Ok(m) => m.permissions(), + Err(_) => continue, + }; + perms.set_mode(0o755); + let _ = fs::set_permissions(entry.path(), perms); + } + } + } +} + +/// Locate the compiled proc-macro dylib by scanning the current directory. +fn find_proc_macro_dylib(name: &str) -> PathBuf { + let prefix = if cfg!(target_os = "windows") { "" } else { "lib" }; + + let ext: &str = if cfg!(target_os = "macos") { + "dylib" + } else if cfg!(target_os = "windows") { + "dll" + } else { + "so" + }; + + let lib_name = format!("{prefix}{name}.{ext}"); + + for entry in fs::read_dir(".").unwrap() { + let entry = entry.unwrap(); + let name = entry.file_name(); + let name = name.to_str().unwrap(); + if name == lib_name { + return entry.path(); + } + } + + panic!("could not find proc-macro dylib for `{name}`"); +} From a677f461cb9c37025d5860efa4c483ec5a5f87b9 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Sun, 22 Mar 2026 12:11:35 -0700 Subject: [PATCH 05/15] `vec::as_mut_slice()`: use lowercase "isize" in safety comment To match other references to that type --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 7796f3b8b2fb3..a2fe730c1acc7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1853,7 +1853,7 @@ impl Vec { // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of // size `len` containing properly-initialized `T`s. Data must not be accessed through any // other pointer for the returned lifetime. Further, `len * size_of::` <= - // `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses. + // `isize::MAX` and allocation does not "wrap" through overflowing memory addresses. // // * Vec API guarantees that self.buf: // * contains only properly-initialized items within 0..len From 178882d54c16460059431fa303d2597ad4f5d132 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Mon, 23 Mar 2026 17:41:19 +0000 Subject: [PATCH 06/15] Use common Timestamp impl in Hermit (attempt 2) --- library/std/src/sys/fs/hermit.rs | 6 +- library/std/src/sys/pal/hermit/mod.rs | 1 + library/std/src/sys/pal/hermit/time.rs | 110 ------------------------- library/std/src/sys/pal/unix/time.rs | 3 +- library/std/src/sys/time/hermit.rs | 22 ++--- 5 files changed, 17 insertions(+), 125 deletions(-) delete mode 100644 library/std/src/sys/pal/hermit/time.rs diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 1e281eb0d9d18..5992766b5a42d 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -109,15 +109,15 @@ pub struct DirBuilder { impl FileAttr { pub fn modified(&self) -> io::Result { - Ok(SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec)) + SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec.into()) } pub fn accessed(&self) -> io::Result { - Ok(SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec)) + SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec.into()) } pub fn created(&self) -> io::Result { - Ok(SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec)) + SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec.into()) } pub fn size(&self) -> u64 { diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index b18dc5b103b59..53f6ddd7065d7 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -22,6 +22,7 @@ use crate::os::raw::c_char; use crate::sys::env; pub mod futex; +#[path = "../unix/time.rs"] pub mod time; pub fn unsupported() -> io::Result { diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs deleted file mode 100644 index b9851eb6754d6..0000000000000 --- a/library/std/src/sys/pal/hermit/time.rs +++ /dev/null @@ -1,110 +0,0 @@ -use hermit_abi::{self, timespec}; - -use crate::cmp::Ordering; -use crate::hash::{Hash, Hasher}; -use crate::time::Duration; - -const NSEC_PER_SEC: i32 = 1_000_000_000; - -#[derive(Copy, Clone, Debug)] -pub struct Timespec { - pub t: timespec, -} - -impl Timespec { - pub const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1); - - pub const MIN: Timespec = Self::new(i64::MIN, 0); - - pub const fn zero() -> Timespec { - Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } - } - - pub const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec { - assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC); - // SAFETY: The assert above checks tv_nsec is within the valid range - Timespec { t: timespec { tv_sec, tv_nsec } } - } - - pub fn sub_timespec(&self, other: &Timespec) -> Result { - fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { - debug_assert!(a >= b); - a.wrapping_sub(b).cast_unsigned() - } - - if self >= other { - // Logic here is identical to Unix version of `Timestamp::sub_timespec`, - // check comments there why operations do not overflow. - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new( - sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec), - (self.t.tv_nsec - other.t.tv_nsec) as u32, - ) - } else { - Duration::new( - sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec), - (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, - ) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?; - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap(); - if nsec >= NSEC_PER_SEC.try_into().unwrap() { - nsec -= u32::try_from(NSEC_PER_SEC).unwrap(); - secs = secs.checked_add(1)?; - } - Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?; - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1)?; - } - Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index fbea94ec84e79..9acc7786b2edd 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -17,7 +17,7 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec { tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64, }; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub(crate) struct Timespec { pub tv_sec: i64, pub tv_nsec: Nanoseconds, @@ -66,6 +66,7 @@ impl Timespec { } } + #[allow(dead_code)] pub fn now(clock: libc::clockid_t) -> Timespec { use crate::mem::MaybeUninit; use crate::sys::cvt; diff --git a/library/std/src/sys/time/hermit.rs b/library/std/src/sys/time/hermit.rs index 18ece2e3010d0..8e8a656ab61ee 100644 --- a/library/std/src/sys/time/hermit.rs +++ b/library/std/src/sys/time/hermit.rs @@ -1,18 +1,21 @@ use hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME}; -use crate::hash::Hash; +use crate::io; use crate::sys::pal::time::Timespec; use crate::time::Duration; +fn clock_gettime(clock: hermit_abi::clockid_t) -> Timespec { + let mut t = hermit_abi::timespec { tv_sec: 0, tv_nsec: 0 }; + let _ = unsafe { hermit_abi::clock_gettime(clock, &raw mut t) }; + Timespec::new(t.tv_sec, t.tv_nsec.into()).unwrap() +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Timespec); impl Instant { pub fn now() -> Instant { - let mut time: Timespec = Timespec::zero(); - let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) }; - - Instant(time) + Instant(clock_gettime(CLOCK_MONOTONIC)) } pub fn checked_sub_instant(&self, other: &Instant) -> Option { @@ -38,15 +41,12 @@ impl SystemTime { pub const MIN: SystemTime = SystemTime(Timespec::MIN); - pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { - SystemTime(Timespec::new(tv_sec, tv_nsec)) + pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { + Ok(SystemTime(Timespec::new(tv_sec, tv_nsec)?)) } pub fn now() -> SystemTime { - let mut time: Timespec = Timespec::zero(); - let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) }; - - SystemTime(time) + SystemTime(clock_gettime(CLOCK_REALTIME)) } pub fn sub_time(&self, other: &SystemTime) -> Result { From ebb91f735be18880ffdc16e1287fd85a70a5aa6b Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 21 Mar 2026 21:53:15 -0400 Subject: [PATCH 07/15] Make `Ipv6Addr::multicast_scope()` exhaustive And make `Ipv6MulticastScope` exhaustive, with `repr(u8)` and the proper discriminant values. The variants for the two reserved scopes are gated behind a perma-unstable feature, in order to avoid committing to names for them. [IETF RFC 4291](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7) and [IETF RFC 7346](https://datatracker.ietf.org/doc/html/rfc7346#section-2) define the list of multicast scopes. The former document says: > scopes labeled "(unassigned)" are available for administrators > to define additional multicast regions. --- library/core/src/net/ip_addr.rs | 102 +++++++++++++++++++++++++------- 1 file changed, 79 insertions(+), 23 deletions(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index a1bfd774710d5..6e16184ca4f69 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -177,15 +177,17 @@ impl Hash for Ipv6Addr { } } -/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2]. +/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2], +/// which updates [IETF RFC 4291 section 2.7]. /// /// # Stability Guarantees /// -/// Not all possible values for a multicast scope have been assigned. -/// Future RFCs may introduce new scopes, which will be added as variants to this enum; -/// because of this the enum is marked as `#[non_exhaustive]`. +/// Scopes 0 and F are currently reserved by IETF, and may be assigned in the future. +/// For this reason, the enum variants for those two scopes are not currently nameable. +/// You can still check for them in your code using `as` casts. /// /// # Examples +/// /// ``` /// #![feature(ip)] /// @@ -204,32 +206,77 @@ impl Hash for Ipv6Addr { /// Some(SiteLocal) => println!("Site-Local scope"), /// Some(OrganizationLocal) => println!("Organization-Local scope"), /// Some(Global) => println!("Global scope"), -/// Some(_) => println!("Unknown scope"), +/// Some(s) => { +/// let snum = s as u8; +/// if matches!(0x0 | 0xF, snum) { +/// println!("Reserved scope {snum:X}") +/// } else { +/// println!("Unassigned scope {snum:X}") +/// } +/// } /// None => println!("Not a multicast address!") /// } -/// /// ``` /// /// [IPv6 multicast address]: Ipv6Addr /// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2 -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +/// [IETF RFC 4291 section 2.7]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.7 +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[unstable(feature = "ip", issue = "27709")] -#[non_exhaustive] +#[repr(u8)] pub enum Ipv6MulticastScope { + /// Reserved by IETF. + #[doc(hidden)] + #[unstable( + feature = "ip_multicast_reserved", + reason = "not yet assigned by IETF", + issue = "none" + )] + Reserved0 = 0x0, /// Interface-Local scope. - InterfaceLocal, + InterfaceLocal = 0x1, /// Link-Local scope. - LinkLocal, + LinkLocal = 0x2, /// Realm-Local scope. - RealmLocal, + RealmLocal = 0x3, /// Admin-Local scope. - AdminLocal, + AdminLocal = 0x4, /// Site-Local scope. - SiteLocal, + SiteLocal = 0x5, + + /// Scope 6. Unassigned, available for administrators + /// to define additional multicast regions. + Unassigned6 = 0x6, + /// Scope 7. Unassigned, available for administrators + /// to define additional multicast regions. + Unassigned7 = 0x7, /// Organization-Local scope. - OrganizationLocal, + OrganizationLocal = 0x8, + /// Scope 9. Unassigned, available for administrators + /// to define additional multicast regions. + Unassigned9 = 0x9, + /// Scope A. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedA = 0xA, + /// Scope B. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedB = 0xB, + /// Scope C. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedC = 0xC, + /// Scope D. Unassigned, available for administrators + /// to define additional multicast regions. + UnassignedD = 0xD, /// Global scope. - Global, + Global = 0xE, + /// Reserved by IETF. + #[doc(hidden)] + #[unstable( + feature = "ip_multicast_reserved", + reason = "not yet assigned by IETF", + issue = "none" + )] + ReservedF = 0xF, } impl IpAddr { @@ -1848,14 +1895,23 @@ impl Ipv6Addr { pub const fn multicast_scope(&self) -> Option { if self.is_multicast() { match self.segments()[0] & 0x000f { - 1 => Some(Ipv6MulticastScope::InterfaceLocal), - 2 => Some(Ipv6MulticastScope::LinkLocal), - 3 => Some(Ipv6MulticastScope::RealmLocal), - 4 => Some(Ipv6MulticastScope::AdminLocal), - 5 => Some(Ipv6MulticastScope::SiteLocal), - 8 => Some(Ipv6MulticastScope::OrganizationLocal), - 14 => Some(Ipv6MulticastScope::Global), - _ => None, + 0x0 => Some(Ipv6MulticastScope::Reserved0), + 0x1 => Some(Ipv6MulticastScope::InterfaceLocal), + 0x2 => Some(Ipv6MulticastScope::LinkLocal), + 0x3 => Some(Ipv6MulticastScope::RealmLocal), + 0x4 => Some(Ipv6MulticastScope::AdminLocal), + 0x5 => Some(Ipv6MulticastScope::SiteLocal), + 0x6 => Some(Ipv6MulticastScope::Unassigned6), + 0x7 => Some(Ipv6MulticastScope::Unassigned7), + 0x8 => Some(Ipv6MulticastScope::OrganizationLocal), + 0x9 => Some(Ipv6MulticastScope::Unassigned9), + 0xA => Some(Ipv6MulticastScope::UnassignedA), + 0xB => Some(Ipv6MulticastScope::UnassignedB), + 0xC => Some(Ipv6MulticastScope::UnassignedC), + 0xD => Some(Ipv6MulticastScope::UnassignedD), + 0xE => Some(Ipv6MulticastScope::Global), + 0xF => Some(Ipv6MulticastScope::ReservedF), + _ => unreachable!(), } } else { None From 3271d4cadfd3e8e69be8e9ee6a561187959791f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2026 08:33:35 +0100 Subject: [PATCH 08/15] uefi: extend comment for TcpStream Send impl --- library/std/src/sys/net/connection/uefi/tcp.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 1e58db0d70468..9522ba69ed311 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -9,7 +9,9 @@ pub(crate) enum Tcp { V4(tcp4::Tcp4), } -// SAFETY: UEFI has no threads. +// SAFETY: UEFI has no regular threads. It does have interrupt handlers and can run code +// on other CPU cores, but those are constrained execution environments that `std` does +// not support, so they are not considered to be relevant for `Send` of `std` types. unsafe impl Send for Tcp {} impl Tcp { From 632d24c144117b7b089eb97b121bc5abd11825bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2026 13:13:06 +0100 Subject: [PATCH 09/15] adjust wording Co-authored-by: David Rheinsberg --- library/std/src/sys/net/connection/uefi/tcp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 9522ba69ed311..85962ce880d55 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -9,9 +9,9 @@ pub(crate) enum Tcp { V4(tcp4::Tcp4), } -// SAFETY: UEFI has no regular threads. It does have interrupt handlers and can run code -// on other CPU cores, but those are constrained execution environments that `std` does -// not support, so they are not considered to be relevant for `Send` of `std` types. +// SAFETY: UEFI has no regular threads, and as per +// std does not support being invoked from "irregular threads" such as interrupt handlers or other +// CPU cores that run outside the scope of UEFI. unsafe impl Send for Tcp {} impl Tcp { From a7fa2dfd8e2bba4cc0833178cfc6e046ca4ef7f3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 25 Mar 2026 21:23:16 +1100 Subject: [PATCH 10/15] Clean up the API for opening/checking incremental-compilation files Returning dedicated structs and enums makes the meaning of each return value more obvious, and provides a more natural home for documentation. The intermediate `load_data` function was unhelpful, and has been inlined into the main function. --- .../src/persist/file_format.rs | 98 ++++++++++++------- .../rustc_incremental/src/persist/load.rs | 49 ++++------ 2 files changed, 77 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 9cec2702a4171..7348ca5c4e440 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -33,7 +33,7 @@ pub(crate) fn write_file_header(stream: &mut FileEncoder, sess: &Session) { stream .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); - let rustc_version = rustc_version(sess.is_nightly_build(), sess.cfg_version); + let rustc_version = rustc_version(sess); assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); stream.emit_raw_bytes(&[rustc_version.len() as u8]); stream.emit_raw_bytes(rustc_version.as_bytes()); @@ -80,26 +80,47 @@ where } } -/// Reads the contents of a file with a file header as defined in this module. -/// -/// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a -/// compatible compiler version. `data` is the entire contents of the file -/// and `pos` points to the first byte after the header. -/// - Returns `Ok(None)` if the file did not exist or was generated by an -/// incompatible version of the compiler. -/// - Returns `Err(..)` if some kind of IO error occurred while reading the -/// file. -pub(crate) fn read_file( +pub(crate) struct OpenFile { + /// A read-only mmap view of the file contents. + pub(crate) mmap: Mmap, + /// File position to start reading normal data from, just after the end of the file header. + pub(crate) start_pos: usize, +} + +pub(crate) enum OpenFileError { + /// Either the file was not found, or one of the header checks failed. + /// + /// These conditions prevent us from reading the file contents, but should + /// not trigger an error or even a warning, because they routinely happen + /// during normal operation: + /// - File-not-found occurs in a fresh build, or after clearing the build directory. + /// - Header-mismatch occurs after upgrading or switching compiler versions. + NotFoundOrHeaderMismatch, + + /// An unexpected I/O error occurred while opening or checking the file. + IoError { err: io::Error }, +} + +impl From for OpenFileError { + fn from(err: io::Error) -> Self { + OpenFileError::IoError { err } + } +} + +/// Tries to open a file that was written by the previous incremental-compilation +/// session, and checks that it was produced by a matching compiler version. +pub(crate) fn open_incremental_file( + sess: &Session, path: &Path, - report_incremental_info: bool, - is_nightly_build: bool, - cfg_version: &'static str, -) -> io::Result> { - let file = match fs::File::open(path) { - Ok(file) => file, - Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), - Err(err) => return Err(err), - }; +) -> Result { + let file = fs::File::open(path).map_err(|err| { + if err.kind() == io::ErrorKind::NotFound { + OpenFileError::NotFoundOrHeaderMismatch + } else { + OpenFileError::IoError { err } + } + })?; + // SAFETY: This process must not modify nor remove the backing file while the memory map lives. // For the dep-graph and the work product index, it is as soon as the decoding is done. // For the query result cache, the memory map is dropped in save_dep_graph before calling @@ -116,8 +137,8 @@ pub(crate) fn read_file( let mut file_magic = [0u8; 4]; file.read_exact(&mut file_magic)?; if file_magic != FILE_MAGIC { - report_format_mismatch(report_incremental_info, path, "Wrong FILE_MAGIC"); - return Ok(None); + report_format_mismatch(sess, path, "Wrong FILE_MAGIC"); + return Err(OpenFileError::NotFoundOrHeaderMismatch); } } @@ -130,8 +151,8 @@ pub(crate) fn read_file( (header_format_version[0] as u16) | ((header_format_version[1] as u16) << 8); if header_format_version != HEADER_FORMAT_VERSION { - report_format_mismatch(report_incremental_info, path, "Wrong HEADER_FORMAT_VERSION"); - return Ok(None); + report_format_mismatch(sess, path, "Wrong HEADER_FORMAT_VERSION"); + return Err(OpenFileError::NotFoundOrHeaderMismatch); } } @@ -143,20 +164,20 @@ pub(crate) fn read_file( let mut buffer = vec![0; rustc_version_str_len]; file.read_exact(&mut buffer)?; - if buffer != rustc_version(is_nightly_build, cfg_version).as_bytes() { - report_format_mismatch(report_incremental_info, path, "Different compiler version"); - return Ok(None); + if buffer != rustc_version(sess).as_bytes() { + report_format_mismatch(sess, path, "Different compiler version"); + return Err(OpenFileError::NotFoundOrHeaderMismatch); } } - let post_header_start_pos = file.position() as usize; - Ok(Some((mmap, post_header_start_pos))) + let start_pos = file.position() as usize; + Ok(OpenFile { mmap, start_pos }) } -fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) { +fn report_format_mismatch(sess: &Session, file: &Path, message: &str) { debug!("read_file: {}", message); - if report_incremental_info { + if sess.opts.unstable_opts.incremental_info { eprintln!( "[incremental] ignoring cache artifact `{}`: {}", file.file_name().unwrap().to_string_lossy(), @@ -168,12 +189,13 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: & /// A version string that hopefully is always different for compiler versions /// with different encodings of incremental compilation artifacts. Contains /// the Git commit hash. -fn rustc_version(nightly_build: bool, cfg_version: &'static str) -> Cow<'static, str> { - if nightly_build { - if let Ok(val) = env::var("RUSTC_FORCE_RUSTC_VERSION") { - return val.into(); - } +fn rustc_version(sess: &Session) -> Cow<'static, str> { + // Allow version string overrides so that tests can produce a header-mismatch on demand. + if sess.is_nightly_build() + && let Ok(env_version) = env::var("RUSTC_FORCE_RUSTC_VERSION") + { + Cow::Owned(env_version) + } else { + Cow::Borrowed(sess.cfg_version) } - - cfg_version.into() } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index f7182e3614dc8..8e27c335b1174 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -1,9 +1,8 @@ //! Code to load the dep-graph from files. -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::Arc; -use rustc_data_structures::memmap::Mmap; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProductMap}; @@ -20,6 +19,7 @@ use super::fs::*; use super::save::build_dep_graph; use super::{file_format, work_product}; use crate::errors; +use crate::persist::file_format::{OpenFile, OpenFileError}; #[derive(Debug)] /// Represents the result of an attempt to load incremental compilation data. @@ -69,23 +69,6 @@ impl LoadResult { } } -fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> { - match file_format::read_file( - path, - sess.opts.unstable_opts.incremental_info, - sess.is_nightly_build(), - sess.cfg_version, - ) { - Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, - Ok(None) => { - // The file either didn't exist or was produced by an incompatible - // compiler version. Neither is an error. - LoadResult::DataOutOfDate - } - Err(err) => LoadResult::LoadDepGraph(path.to_path_buf(), err), - } -} - fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) { debug!("delete_dirty_work_product({:?})", swp); work_product::delete_workproduct_files(sess, &swp.work_product); @@ -113,12 +96,12 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkPr // when trying to load work products. if sess.incr_comp_session_dir_opt().is_some() { let work_products_path = work_products_path(sess); - let load_result = load_data(&work_products_path, sess); - if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { + if let Ok(OpenFile { mmap, start_pos }) = + file_format::open_incremental_file(sess, &work_products_path) + { // Decode the list of work_products - let Ok(mut work_product_decoder) = MemDecoder::new(&work_products_data[..], start_pos) - else { + let Ok(mut work_product_decoder) = MemDecoder::new(&mmap[..], start_pos) else { sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path }); return LoadResult::DataOutOfDate; }; @@ -147,11 +130,11 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkPr let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); - match load_data(&path, sess) { - LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, - LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err), - LoadResult::Ok { data: (bytes, start_pos) } => { - let Ok(mut decoder) = MemDecoder::new(&bytes, start_pos) else { + match file_format::open_incremental_file(sess, &path) { + Err(OpenFileError::NotFoundOrHeaderMismatch) => LoadResult::DataOutOfDate, + Err(OpenFileError::IoError { err }) => LoadResult::LoadDepGraph(path.to_owned(), err), + Ok(OpenFile { mmap, start_pos }) => { + let Ok(mut decoder) = MemDecoder::new(&mmap, start_pos) else { sess.dcx().emit_warn(errors::CorruptFile { path: &path }); return LoadResult::DataOutOfDate; }; @@ -191,15 +174,17 @@ pub fn load_query_result_cache(sess: &Session) -> Option { let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); let path = query_cache_path(sess); - match load_data(&path, sess) { - LoadResult::Ok { data: (bytes, start_pos) } => { - let cache = OnDiskCache::new(sess, bytes, start_pos).unwrap_or_else(|()| { + match file_format::open_incremental_file(sess, &path) { + Ok(OpenFile { mmap, start_pos }) => { + let cache = OnDiskCache::new(sess, mmap, start_pos).unwrap_or_else(|()| { sess.dcx().emit_warn(errors::CorruptFile { path: &path }); OnDiskCache::new_empty() }); Some(cache) } - _ => Some(OnDiskCache::new_empty()), + Err(OpenFileError::NotFoundOrHeaderMismatch | OpenFileError::IoError { .. }) => { + Some(OnDiskCache::new_empty()) + } } } From 505dabc2a06f70708e2cd825afe9e5e215cfd699 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 26 Mar 2026 16:57:52 +1100 Subject: [PATCH 11/15] Tiny improvements to incremental header reads/writes The standard library has helper methods for converting integers to/from little-endian bytes, for checked conversion from `usize` to `u8`, and for treating `&mut T` as `&mut [T; 1]`. --- .../src/persist/file_format.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 7348ca5c4e440..c47540fe385ba 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -12,7 +12,7 @@ use std::borrow::Cow; use std::io::{self, Read}; use std::path::{Path, PathBuf}; -use std::{env, fs}; +use std::{array, env, fs}; use rustc_data_structures::memmap::Mmap; use rustc_serialize::Encoder; @@ -30,12 +30,12 @@ const HEADER_FORMAT_VERSION: u16 = 0; pub(crate) fn write_file_header(stream: &mut FileEncoder, sess: &Session) { stream.emit_raw_bytes(FILE_MAGIC); - stream - .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); + stream.emit_raw_bytes(&u16::to_le_bytes(HEADER_FORMAT_VERSION)); let rustc_version = rustc_version(sess); - assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); - stream.emit_raw_bytes(&[rustc_version.len() as u8]); + let rustc_version_len = + u8::try_from(rustc_version.len()).expect("version string should not exceed 255 bytes"); + stream.emit_raw_bytes(&[rustc_version_len]); stream.emit_raw_bytes(rustc_version.as_bytes()); } @@ -147,8 +147,7 @@ pub(crate) fn open_incremental_file( debug_assert!(size_of_val(&HEADER_FORMAT_VERSION) == 2); let mut header_format_version = [0u8; 2]; file.read_exact(&mut header_format_version)?; - let header_format_version = - (header_format_version[0] as u16) | ((header_format_version[1] as u16) << 8); + let header_format_version = u16::from_le_bytes(header_format_version); if header_format_version != HEADER_FORMAT_VERSION { report_format_mismatch(sess, path, "Wrong HEADER_FORMAT_VERSION"); @@ -158,10 +157,9 @@ pub(crate) fn open_incremental_file( // Check RUSTC_VERSION { - let mut rustc_version_str_len = [0u8; 1]; - file.read_exact(&mut rustc_version_str_len)?; - let rustc_version_str_len = rustc_version_str_len[0] as usize; - let mut buffer = vec![0; rustc_version_str_len]; + let mut rustc_version_str_len = 0u8; + file.read_exact(array::from_mut(&mut rustc_version_str_len))?; + let mut buffer = vec![0; usize::from(rustc_version_str_len)]; file.read_exact(&mut buffer)?; if buffer != rustc_version(sess).as_bytes() { From afe3ab6ac5681668a92fb4be7a116bf1be6fb863 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 26 Mar 2026 00:08:43 +0000 Subject: [PATCH 12/15] chore(deps): update rust crate tar to v0.4.45 --- Cargo.lock | 4 ++-- src/bootstrap/Cargo.lock | 4 ++-- src/bootstrap/Cargo.toml | 2 +- src/tools/build-manifest/Cargo.toml | 2 +- src/tools/opt-dist/Cargo.toml | 2 +- src/tools/rust-installer/Cargo.toml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85997e1886f1e..3cb3293efe65c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5461,9 +5461,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index d694f8e13f111..a6d8d4610521b 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -757,9 +757,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 7187a5a951de0..9b1039bbc4f6a 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -50,7 +50,7 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" sha2 = "0.10" -tar = { version = "0.4.44", default-features = false } +tar = { version = "0.4.45", default-features = false } termcolor = "1.4" toml = "0.5" walkdir = "2.4" diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index c0271bbc89b53..2b0afae76da42 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -10,7 +10,7 @@ serde_json = "1.0" anyhow = "1.0.32" flate2 = "1.0.26" xz2 = "0.1.7" -tar = "0.4.29" +tar = "0.4.45" sha2 = "0.10.1" rayon = "1.5.1" hex = "0.4.2" diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index 29d302b52566a..9b54f62da9bdf 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -13,7 +13,7 @@ humansize = "2" sysinfo = { version = "0.38.4", default-features = false, features = ["disk"] } fs_extra = "1" camino = "1" -tar = "0.4" +tar = "0.4.45" xz = { version = "0.1", package = "xz2" } serde_json = "1" glob = "0.3" diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml index cdd867c5f1577..e0c93e3c4477b 100644 --- a/src/tools/rust-installer/Cargo.toml +++ b/src/tools/rust-installer/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" anyhow = "1.0.19" flate2 = "1.0.1" rayon = "1.0" -tar = "0.4.38" +tar = "0.4.45" walkdir = "2" xz2 = "0.1.4" From 0c05f6c47875ec444e20411526856999e670b493 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 27 Mar 2026 10:44:41 -0400 Subject: [PATCH 13/15] Add ignore-cross-compile to incremental-finalize-fail The test needs proc-macros to function --- tests/run-make/incremental-finalize-fail/rmake.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-make/incremental-finalize-fail/rmake.rs b/tests/run-make/incremental-finalize-fail/rmake.rs index 36ba2a48ca46b..96dae4856ca05 100644 --- a/tests/run-make/incremental-finalize-fail/rmake.rs +++ b/tests/run-make/incremental-finalize-fail/rmake.rs @@ -1,3 +1,6 @@ +//@ ignore-cross-compile +//@ needs-crate-type: proc-macro + //! Test that a failure to finalize the incremental compilation session directory //! (i.e., the rename from "-working" to the SVH-based name) results in a //! note, not an ICE, and that the compilation output is still produced. From 4ca63285361b446fd2ab17bedf2d6a3bc81d5723 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 27 Mar 2026 18:50:08 -0400 Subject: [PATCH 14/15] Remove `repr(u8)` --- library/core/src/net/ip_addr.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 6e16184ca4f69..1d303e7d307dd 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -223,7 +223,6 @@ impl Hash for Ipv6Addr { /// [IETF RFC 4291 section 2.7]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.7 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[unstable(feature = "ip", issue = "27709")] -#[repr(u8)] pub enum Ipv6MulticastScope { /// Reserved by IETF. #[doc(hidden)] From d470684a43b467924aa6338ae2e4f84fcefb5ab4 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 28 Mar 2026 14:18:26 +1100 Subject: [PATCH 15/15] Revert "Unstable book options parser" This reverts commit 6fd846676801486d304030698cc8dac261b98680, reversing changes made to fda6d37bb88ee12fd50fa54d15859f1f91b74f55. --- Cargo.lock | 2 - compiler/rustc_session/src/options.rs | 590 +++++++++++++++++- .../rustc_session/src/options/unstable.rs | 585 ----------------- src/tools/unstable-book-gen/Cargo.toml | 2 - src/tools/unstable-book-gen/src/main.rs | 200 +----- src/tools/unstable-book-gen/src/tests.rs | 73 --- 6 files changed, 587 insertions(+), 865 deletions(-) delete mode 100644 compiler/rustc_session/src/options/unstable.rs delete mode 100644 src/tools/unstable-book-gen/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index e7f713936f16e..91daa229a95e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6088,8 +6088,6 @@ name = "unstable-book-gen" version = "0.1.0" dependencies = [ "num-traits", - "proc-macro2", - "syn 2.0.110", "tidy", ] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a9db6979cc797..7abaae1c17606 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -605,10 +605,6 @@ macro_rules! tmod_enum { /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of /// generated code to parse an option into its respective field in the struct. There are a few /// hand-written parsers for parsing specific types of values in this module. -/// -/// Note: this macro's invocation is also parsed by a `syn`-based parser in -/// `src/tools/unstable-book-gen/src/main.rs` to extract unstable option names and descriptions. -/// If the format of this macro changes, that parser may need to be updated as well. macro_rules! options { ($struct_name:ident, $tmod_enum_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr, $($( #[$attr:meta] )* $opt:ident : $t:ty = ( @@ -2219,4 +2215,588 @@ options! { // - src/doc/rustc/src/codegen-options/index.md } -include!("options/unstable.rs"); +options! { + UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable", + + // If you add a new option, please update: + // - compiler/rustc_interface/src/tests.rs + // - src/doc/unstable-book/src/compiler-flags + + // tidy-alphabetical-start + allow_features: Option> = (None, parse_opt_comma_list, [TRACKED], + "only allow the listed language features to be enabled in code (comma separated)"), + always_encode_mir: bool = (false, parse_bool, [TRACKED], + "encode MIR of all functions into the crate metadata (default: no)"), + annotate_moves: AnnotateMoves = (AnnotateMoves::Disabled, parse_annotate_moves, [TRACKED], + "emit debug info for compiler-generated move and copy operations \ + to make them visible in profilers. Can be a boolean or a size limit in bytes (default: disabled)"), + assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], + "assert that the incremental cache is in given state: \ + either `loaded` or `not-loaded`."), + assume_incomplete_release: bool = (false, parse_bool, [TRACKED], + "make cfg(version) treat the current version as incomplete (default: no)"), + autodiff: Vec = (Vec::new(), parse_autodiff, [TRACKED], + "a list of autodiff flags to enable + Mandatory setting: + `=Enable` + Optional extra settings: + `=PrintTA` + `=PrintAA` + `=PrintPerf` + `=PrintSteps` + `=PrintModBefore` + `=PrintModAfter` + `=PrintModFinal` + `=PrintPasses`, + `=NoPostopt` + `=LooseTypes` + `=Inline` + Multiple options can be combined with commas."), + #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")] + binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], + "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ + (default: no)"), + box_noalias: bool = (true, parse_bool, [TRACKED], + "emit noalias metadata for box (default: yes)"), + branch_protection: Option = (None, parse_branch_protection, [TRACKED TARGET_MODIFIER], + "set options for branch target identification and pointer authentication on AArch64"), + build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED], + "whether the stable interface is being built"), + cache_proc_macros: bool = (false, parse_bool, [TRACKED], + "cache the results of derive proc macro invocations (potentially unsound!) (default: no"), + cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], + "instrument control-flow architecture protection"), + check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED], + "show all expected values in check-cfg diagnostics (default: no)"), + checksum_hash_algorithm: Option = (None, parse_cargo_src_file_hash, [TRACKED], + "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"), + codegen_backend: Option = (None, parse_opt_string, [TRACKED], + "the backend to use"), + codegen_source_order: bool = (false, parse_bool, [UNTRACKED], + "emit mono items in the order of spans in source files (default: no)"), + contract_checks: Option = (None, parse_opt_bool, [TRACKED], + "emit runtime checks for contract pre- and post-conditions (default: no)"), + coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED], + "control details of coverage instrumentation"), + crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], + "inject the given attribute in the crate"), + cross_crate_inline_threshold: InliningThreshold = (InliningThreshold::Sometimes(100), parse_inlining_threshold, [TRACKED], + "threshold to allow cross crate inlining of functions"), + debug_info_for_profiling: bool = (false, parse_bool, [TRACKED], + "emit discriminators and other data necessary for AutoFDO"), + debug_info_type_line_numbers: bool = (false, parse_bool, [TRACKED], + "emit type and line information for additional data types (default: no)"), + debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED], + "compress debug info sections (none, zlib, zstd, default: none)"), + deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], + "deduplicate identical diagnostics (default: yes)"), + default_visibility: Option = (None, parse_opt_symbol_visibility, [TRACKED], + "overrides the `default_visibility` setting of the target"), + dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], + "in dep-info output, omit targets for tracking dependencies of the dep-info files \ + themselves (default: no)"), + direct_access_external_data: Option = (None, parse_opt_bool, [TRACKED], + "Direct or use GOT indirect to reference external data symbols"), + dual_proc_macros: bool = (false, parse_bool, [TRACKED], + "load proc macros for both target and host, but only link to the target (default: no)"), + dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], + "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \ + (default: no)"), + dump_mir: Option = (None, parse_opt_string, [UNTRACKED], + "dump MIR state to file. + `val` is used to select which passes and functions to dump. For example: + `all` matches all passes and functions, + `foo` matches all passes for functions whose name contains 'foo', + `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo', + `foo | bar` all passes for function names containing 'foo' or 'bar'."), + dump_mir_dataflow: bool = (false, parse_bool, [UNTRACKED], + "in addition to `.mir` files, create graphviz `.dot` files with dataflow results \ + (default: no)"), + dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED], + "the directory the MIR is dumped into (default: `mir_dump`)"), + dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED], + "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"), + dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED], + "exclude the pass number when dumping MIR (used in tests) (default: no)"), + dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], + "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), + dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled, + parse_switch_with_opt_path, [UNTRACKED], + "output statistics about monomorphization collection"), + dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED], + "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"), + #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")] + dwarf_version: Option = (None, parse_opt_number, [TRACKED], + "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), + dylib_lto: bool = (false, parse_bool, [UNTRACKED], + "enables LTO for dylib crate type"), + eagerly_emit_delayed_bugs: bool = (false, parse_bool, [UNTRACKED], + "emit delayed bugs eagerly as errors instead of stashing them and emitting \ + them only if an error has not been emitted"), + ehcont_guard: bool = (false, parse_bool, [TRACKED], + "generate Windows EHCont Guard tables"), + embed_metadata: bool = (true, parse_bool, [TRACKED], + "embed metadata in rlibs and dylibs (default: yes)"), + embed_source: bool = (false, parse_bool, [TRACKED], + "embed source text in DWARF debug sections (default: no)"), + emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], + "emit a section containing stack size metadata (default: no)"), + emscripten_wasm_eh: bool = (true, parse_bool, [TRACKED], + "Use WebAssembly error handling for wasm32-unknown-emscripten"), + enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], + "enforce the type length limit when monomorphizing instances in codegen"), + experimental_default_bounds: bool = (false, parse_bool, [TRACKED], + "enable default bounds for experimental group of auto traits"), + export_executable_symbols: bool = (false, parse_bool, [TRACKED], + "export symbols from executables, as if they were dynamic libraries"), + external_clangrt: bool = (false, parse_bool, [UNTRACKED], + "rely on user specified linker commands to find clangrt"), + extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], + "turns on more checks to detect const UB, which can be slow (default: no)"), + #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")] + fewer_names: Option = (None, parse_opt_bool, [TRACKED], + "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ + (default: no)"), + fixed_x18: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "make the x18 register reserved on AArch64 (default: no)"), + flatten_format_args: bool = (true, parse_bool, [TRACKED], + "flatten nested format_args!() and literals into a simplified format_args!() call \ + (default: yes)"), + fmt_debug: FmtDebug = (FmtDebug::Full, parse_fmt_debug, [TRACKED], + "how detailed `#[derive(Debug)]` should be. `full` prints types recursively, \ + `shallow` prints only type names, `none` prints nothing and disables `{:?}`. (default: `full`)"), + force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], + "force all crates to be `rustc_private` unstable (default: no)"), + function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED], + "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"), + function_sections: Option = (None, parse_opt_bool, [TRACKED], + "whether each function should go in its own section"), + future_incompat_test: bool = (false, parse_bool, [UNTRACKED], + "forces all lints to be future incompatible, used for internal testing (default: no)"), + graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], + "use dark-themed colors in graphviz output (default: no)"), + graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], + "use the given `fontname` in graphviz output; can be overridden by setting \ + environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), + has_thread_local: Option = (None, parse_opt_bool, [TRACKED], + "explicitly enable the `cfg(target_thread_local)` directive"), + help: bool = (false, parse_no_value, [UNTRACKED], "Print unstable compiler options"), + higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED], + "allow deducing higher-ranked outlives assumptions from coroutines when proving auto traits"), + hint_mostly_unused: bool = (false, parse_bool, [TRACKED], + "hint that most of this crate will go unused, to minimize work for uncalled functions"), + human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], + "generate human-readable, predictable names for codegen units (default: no)"), + identify_regions: bool = (false, parse_bool, [UNTRACKED], + "display unnamed regions as `'`, using a non-ident unique id (default: no)"), + ignore_directory_in_diagnostics_source_blocks: Vec = (Vec::new(), parse_string_push, [UNTRACKED], + "do not display the source code block in diagnostics for files in the directory"), + incremental_ignore_spans: bool = (false, parse_bool, [TRACKED], + "ignore spans during ICH computation -- used for testing (default: no)"), + incremental_info: bool = (false, parse_bool, [UNTRACKED], + "print high-level information about incremental reuse (or the lack thereof) \ + (default: no)"), + incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], + "verify extended properties for incr. comp. (default: no): + - hashes of green query instances + - hash collisions of query keys + - hash collisions when creating dep-nodes"), + indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "add `cs` prefix to `call` and `jmp` to indirect thunks (default: no)"), + inline_llvm: bool = (true, parse_bool, [TRACKED], + "enable LLVM inlining (default: yes)"), + inline_mir: Option = (None, parse_opt_bool, [TRACKED], + "enable MIR inlining (default: no)"), + inline_mir_forwarder_threshold: Option = (None, parse_opt_number, [TRACKED], + "inlining threshold when the caller is a simple forwarding function (default: 30)"), + inline_mir_hint_threshold: Option = (None, parse_opt_number, [TRACKED], + "inlining threshold for functions with inline hint (default: 100)"), + inline_mir_preserve_debug: Option = (None, parse_opt_bool, [TRACKED], + "when MIR inlining, whether to preserve debug info for callee variables \ + (default: preserve for debuginfo != None, otherwise remove)"), + inline_mir_threshold: Option = (None, parse_opt_number, [TRACKED], + "a default MIR inlining threshold (default: 50)"), + input_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about AST and HIR (default: no)"), + instrument_mcount: bool = (false, parse_bool, [TRACKED], + "insert function instrument code for mcount-based tracing (default: no)"), + instrument_xray: Option = (None, parse_instrument_xray, [TRACKED], + "insert function instrument code for XRay-based tracing (default: no) + Optional extra settings: + `=always` + `=never` + `=ignore-loops` + `=instruction-threshold=N` + `=skip-entry` + `=skip-exit` + Multiple options can be combined with commas."), + large_data_threshold: Option = (None, parse_opt_number, [TRACKED], + "set the threshold for objects to be stored in a \"large data\" section \ + (only effective with -Ccode-model=medium, default: 65536)"), + layout_seed: Option = (None, parse_opt_number, [TRACKED], + "seed layout randomization"), + link_directives: bool = (true, parse_bool, [TRACKED], + "honor #[link] directives in the compiled crate (default: yes)"), + link_native_libraries: bool = (true, parse_bool, [UNTRACKED], + "link native libraries in the linker invocation (default: yes)"), + link_only: bool = (false, parse_bool, [TRACKED], + "link the `.rlink` file generated by `-Z no-link` (default: no)"), + lint_llvm_ir: bool = (false, parse_bool, [TRACKED], + "lint LLVM IR (default: no)"), + lint_mir: bool = (false, parse_bool, [UNTRACKED], + "lint MIR before and after each transformation"), + llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED], + "a list of module flags to pass to LLVM (space separated)"), + llvm_plugins: Vec = (Vec::new(), parse_list, [TRACKED], + "a list LLVM plugins to enable (space separated)"), + llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], + "generate JSON tracing data file from LLVM data (default: no)"), + location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED], + "what location details should be tracked when using caller_location, either \ + `none`, or a comma separated list of location details, for which \ + valid options are `file`, `line`, and `column` (default: `file,line,column`)"), + ls: Vec = (Vec::new(), parse_list, [UNTRACKED], + "decode and print various parts of the crate metadata for a library crate \ + (space separated)"), + macro_backtrace: bool = (false, parse_bool, [UNTRACKED], + "show macro backtraces (default: no)"), + macro_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about macro expansions (default: no)"), + maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED], + "save as much information as possible about the correspondence between MIR and HIR \ + as source scopes (default: no)"), + merge_functions: Option = (None, parse_merge_functions, [TRACKED], + "control the operation of the MergeFunctions LLVM pass, taking \ + the same values as the target option of the same name"), + meta_stats: bool = (false, parse_bool, [UNTRACKED], + "gather metadata statistics (default: no)"), + metrics_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], + "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"), + min_function_alignment: Option = (None, parse_align, [TRACKED], + "align all functions to at least this many bytes. Must be a power of 2"), + min_recursion_limit: Option = (None, parse_opt_number, [TRACKED], + "set a minimum recursion limit (final limit = max(this, recursion_limit_from_crate))"), + mir_emit_retag: bool = (false, parse_bool, [TRACKED], + "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ + (default: no)"), + mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED], + "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \ + specified passes to be enabled, overriding all other checks. In particular, this will \ + enable unsound (known-buggy and hence usually disabled) passes without further warning! \ + Passes that are not specified are enabled or disabled by other flags as usual."), + mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED], + "include extra comments in mir pretty printing, like line numbers and statement indices, \ + details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"), + mir_opt_bisect_limit: Option = (None, parse_opt_number, [TRACKED], + "limit the number of MIR optimization pass executions (global across all bodies). \ + Pass executions after this limit are skipped and reported. (default: no limit)"), + #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] + mir_opt_level: Option = (None, parse_opt_number, [TRACKED], + "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), + mir_preserve_ub: bool = (false, parse_bool, [TRACKED], + "keep place mention statements and reads in trivial SwitchInt terminators, which are interpreted \ + e.g., by miri; implies -Zmir-opt-level=0 (default: no)"), + mir_strip_debuginfo: MirStripDebugInfo = (MirStripDebugInfo::None, parse_mir_strip_debuginfo, [TRACKED], + "Whether to remove some of the MIR debug info from methods. Default: None"), + move_size_limit: Option = (None, parse_opt_number, [TRACKED], + "the size at which the `large_assignments` lint starts to be emitted"), + mutable_noalias: bool = (true, parse_bool, [TRACKED], + "emit noalias metadata for mutable references (default: yes)"), + namespaced_crates: bool = (false, parse_bool, [TRACKED], + "allow crates to be namespaced by other crates (default: no)"), + next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED], + "enable and configure the next generation trait solver used by rustc"), + nll_facts: bool = (false, parse_bool, [UNTRACKED], + "dump facts from NLL analysis into side files (default: no)"), + nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED], + "the directory the NLL facts are dumped into (default: `nll-facts`)"), + no_analysis: bool = (false, parse_no_value, [UNTRACKED], + "parse and expand the source, but run no analysis"), + no_codegen: bool = (false, parse_no_value, [TRACKED_NO_CRATE_HASH], + "run all passes except codegen; no output"), + no_generate_arange_section: bool = (false, parse_no_value, [TRACKED], + "omit DWARF address ranges that give faster lookups"), + no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED], + "disable the compatibility version of the `implied_bounds_ty` query"), + no_leak_check: bool = (false, parse_no_value, [UNTRACKED], + "disable the 'leak check' for subtyping; unsound, but useful for tests"), + no_link: bool = (false, parse_no_value, [TRACKED], + "compile without linking"), + no_parallel_backend: bool = (false, parse_no_value, [UNTRACKED], + "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), + no_profiler_runtime: bool = (false, parse_no_value, [TRACKED], + "prevent automatic injection of the profiler_builtins crate"), + no_steal_thir: bool = (false, parse_bool, [UNTRACKED], + "don't steal the THIR when we're done with it; useful for rustc drivers (default: no)"), + no_trait_vptr: bool = (false, parse_no_value, [TRACKED], + "disable generation of trait vptr in vtable for upcasting"), + no_unique_section_names: bool = (false, parse_bool, [TRACKED], + "do not use unique names for text and data sections when -Z function-sections is used"), + normalize_docs: bool = (false, parse_bool, [TRACKED], + "normalize associated items in rustdoc when generating documentation"), + offload: Vec = (Vec::new(), parse_offload, [TRACKED], + "a list of offload flags to enable + Mandatory setting: + `=Enable` + Currently the only option available"), + on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED], + "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"), + osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], + "pass `-install_name @rpath/...` to the macOS linker (default: no)"), + packed_bundled_libs: bool = (false, parse_bool, [TRACKED], + "change rlib format to store native libraries as archives"), + panic_abort_tests: bool = (false, parse_bool, [TRACKED], + "support compiling tests with panic=abort (default: no)"), + panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED], + "panic strategy for panics in drops"), + parse_crate_root_only: bool = (false, parse_bool, [UNTRACKED], + "parse the crate root file only; do not parse other files, compile, assemble, or link \ + (default: no)"), + patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED], + "nop padding at function entry"), + plt: Option = (None, parse_opt_bool, [TRACKED], + "whether to use the PLT when calling into shared libraries; + only has effect for PIC code on systems with ELF binaries + (default: PLT is disabled if full relro is enabled on x86_64)"), + polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED], + "enable polonius-based borrow-checker (default: no)"), + pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED], + "a single extra argument to prepend the linker invocation (can be used several times)"), + pre_link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], + "extra arguments to prepend to the linker invocation (space separated)"), + precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED], + "use a more precise version of drop elaboration for matches on enums (default: yes). \ + This results in better codegen, but has caused miscompilations on some tier 2 platforms. \ + See #77382 and #74551."), + #[rustc_lint_opt_deny_field_access("use `Session::print_codegen_stats` instead of this field")] + print_codegen_stats: bool = (false, parse_bool, [UNTRACKED], + "print codegen statistics (default: no)"), + print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], + "print the LLVM optimization passes being run (default: no)"), + print_mono_items: bool = (false, parse_bool, [UNTRACKED], + "print the result of the monomorphization collection pass (default: no)"), + print_type_sizes: bool = (false, parse_bool, [UNTRACKED], + "print layout information for each type encountered (default: no)"), + proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], + "show backtraces for panics during proc-macro execution (default: no)"), + proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread, + parse_proc_macro_execution_strategy, [UNTRACKED], + "how to run proc-macro code (default: same-thread)"), + profile_closures: bool = (false, parse_no_value, [UNTRACKED], + "profile size of closures"), + profile_sample_use: Option = (None, parse_opt_pathbuf, [TRACKED], + "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), + profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], + "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"), + query_dep_graph: bool = (false, parse_bool, [UNTRACKED], + "enable queries of the dependency graph for regression testing (default: no)"), + randomize_layout: bool = (false, parse_bool, [TRACKED], + "randomize the layout of types (default: no)"), + reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "On x86-32 targets, it overrides the default ABI to return small structs in registers. + It is UNSOUND to link together crates that use different values for this flag!"), + regparm: Option = (None, parse_opt_number, [TRACKED TARGET_MODIFIER], + "On x86-32 targets, setting this to N causes the compiler to pass N arguments \ + in registers EAX, EDX, and ECX instead of on the stack for\ + \"C\", \"cdecl\", and \"stdcall\" fn.\ + It is UNSOUND to link together crates that use different values for this flag!"), + relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], + "whether ELF relocations can be relaxed"), + remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], + "remap paths under the current working directory to this path prefix"), + remark_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], + "directory into which to write optimization remarks (if not specified, they will be \ +written to standard error output)"), + retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"), + retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \ + target features (default: no)"), + #[rustc_lint_opt_deny_field_access("use `Session::sanitizers()` instead of this field")] + sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER], + "use a sanitizer"), + sanitizer_cfi_canonical_jump_tables: Option = (Some(true), parse_opt_bool, [TRACKED], + "enable canonical jump tables (default: yes)"), + sanitizer_cfi_generalize_pointers: Option = (None, parse_opt_bool, [TRACKED], + "enable generalizing pointer types (default: no)"), + sanitizer_cfi_normalize_integers: Option = (None, parse_opt_bool, [TRACKED TARGET_MODIFIER], + "enable normalizing integer types (default: no)"), + sanitizer_dataflow_abilist: Vec = (Vec::new(), parse_comma_list, [TRACKED], + "additional ABI list files that control how shadow parameters are passed (comma separated)"), + sanitizer_kcfi_arity: Option = (None, parse_opt_bool, [TRACKED], + "enable KCFI arity indicator (default: no)"), + sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED], + "enable origins tracking in MemorySanitizer"), + sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], + "enable recovery for selected sanitizers"), + saturating_float_casts: Option = (None, parse_opt_bool, [TRACKED], + "make float->int casts UB-free: numbers outside the integer type's range are clipped to \ + the max/min integer respectively, and NaN is mapped to 0 (default: yes)"), + self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled, + parse_switch_with_opt_path, [UNTRACKED], + "run the self profiler and output the raw event data"), + self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED], + "counter used by the self profiler (default: `wall-time`), one of: + `wall-time` (monotonic clock, i.e. `std::time::Instant`) + `instructions:u` (retired instructions, userspace-only) + `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)" + ), + /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs + self_profile_events: Option> = (None, parse_opt_comma_list, [UNTRACKED], + "specify the events recorded by the self profiler; + for example: `-Z self-profile-events=default,query-keys` + all options: none, all, default, generic-activity, query-provider, query-cache-hit + query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"), + share_generics: Option = (None, parse_opt_bool, [TRACKED], + "make the current crate share its generic instantiations"), + shell_argfiles: bool = (false, parse_bool, [UNTRACKED], + "allow argument files to be specified with POSIX \"shell-style\" argument quoting"), + simulate_remapped_rust_src_base: Option = (None, parse_opt_pathbuf, [TRACKED], + "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ + to rust's source base directory. only meant for testing purposes"), + small_data_threshold: Option = (None, parse_opt_number, [TRACKED], + "Set the threshold for objects to be stored in a \"small data\" section"), + span_debug: bool = (false, parse_bool, [UNTRACKED], + "forward proc_macro::Span's `Debug` impl to `Span`"), + /// o/w tests have closure@path + span_free_formats: bool = (false, parse_bool, [UNTRACKED], + "exclude spans when debug-printing compiler state (default: no)"), + split_dwarf_inlining: bool = (false, parse_bool, [TRACKED], + "provide minimal debug info in the object/executable to facilitate online \ + symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), + split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED], + "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) + (default: `split`) + + `split`: sections which do not require relocation are written into a DWARF object (`.dwo`) + file which is ignored by the linker + `single`: sections which do not require relocation are written into object file but ignored + by the linker"), + split_dwarf_out_dir : Option = (None, parse_opt_pathbuf, [TRACKED], + "location for writing split DWARF objects (`.dwo`) if enabled"), + split_lto_unit: Option = (None, parse_opt_bool, [TRACKED], + "enable LTO unit splitting (default: no)"), + src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], + "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), + #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] + stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], + "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), + staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED], + "allow staticlibs to have rust dylib dependencies"), + staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED], + "prefer dynamic linking to static linking for staticlibs (default: no)"), + strict_init_checks: bool = (false, parse_bool, [TRACKED], + "control if mem::uninitialized and mem::zeroed panic on more UB"), + #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")] + teach: bool = (false, parse_bool, [TRACKED], + "show extended diagnostic help (default: no)"), + temps_dir: Option = (None, parse_opt_string, [UNTRACKED], + "the directory the intermediate files are written to"), + terminal_urls: TerminalUrl = (TerminalUrl::No, parse_terminal_url, [UNTRACKED], + "use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output"), + #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] + thinlto: Option = (None, parse_opt_bool, [TRACKED], + "enable ThinLTO when possible"), + /// We default to 1 here since we want to behave like + /// a sequential compiler for now. This'll likely be adjusted + /// in the future. Note that -Zthreads=0 is the way to get + /// the num_cpus behavior. + #[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")] + threads: usize = (1, parse_threads, [UNTRACKED], + "use a thread pool with N threads"), + time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], + "measure time of each LLVM pass (default: no)"), + time_passes: bool = (false, parse_bool, [UNTRACKED], + "measure time of each rustc pass (default: no)"), + time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED], + "the format to use for -Z time-passes (`text` (default) or `json`)"), + tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED], + "sets a tiny, non-configurable limit for const eval; useful for compiler tests"), + #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")] + tls_model: Option = (None, parse_tls_model, [TRACKED], + "choose the TLS model to use (`rustc --print tls-models` for details)"), + trace_macros: bool = (false, parse_bool, [UNTRACKED], + "for every macro invocation, print its name and arguments (default: no)"), + track_diagnostics: bool = (false, parse_bool, [UNTRACKED], + "tracks where in rustc a diagnostic was emitted"), + translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED], + "translate remapped paths into local paths when possible (default: yes)"), + trap_unreachable: Option = (None, parse_opt_bool, [TRACKED], + "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), + treat_err_as_bug: Option> = (None, parse_treat_err_as_bug, [TRACKED], + "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \ + default if specified without a value: 1 - treat the first error as bug)"), + trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], + "in diagnostics, use heuristics to shorten paths referring to items"), + tune_cpu: Option = (None, parse_opt_string, [TRACKED], + "select processor to schedule for (`rustc --print target-cpus` for details)"), + #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_borrowck` instead of this field")] + typing_mode_borrowck: bool = (false, parse_bool, [TRACKED], + "enable `TypingMode::Borrowck`, changing the way opaque types are handled during MIR borrowck"), + #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] + ub_checks: Option = (None, parse_opt_bool, [TRACKED], + "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), + ui_testing: bool = (false, parse_bool, [UNTRACKED], + "emit compiler diagnostics in a form suitable for UI testing (default: no)"), + uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED], + "allow generating const initializers with mixed init/uninit chunks, \ + and set the maximum number of chunks for which this is allowed (default: 16)"), + unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED], + "take the brakes off const evaluation. NOTE: this is unsound (default: no)"), + unpretty: Option = (None, parse_unpretty, [UNTRACKED], + "present the input source, unstable (and less-pretty) variants; + `normal`, `identified`, + `expanded`, `expanded,identified`, + `expanded,hygiene` (with internal representations), + `ast-tree` (raw AST before expansion), + `ast-tree,expanded` (raw AST after expansion), + `hir` (the HIR), `hir,identified`, + `hir,typed` (HIR with types for each node), + `hir-tree` (dump the raw HIR), + `thir-tree`, `thir-flat`, + `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), + unsound_mir_opts: bool = (false, parse_bool, [TRACKED], + "enable unsound and buggy MIR optimizations (default: no)"), + /// This name is kind of confusing: Most unstable options enable something themselves, while + /// this just allows "normal" options to be feature-gated. + /// + /// The main check for `-Zunstable-options` takes place separately from the + /// usual parsing of `-Z` options (see [`crate::config::nightly_options`]), + /// so this boolean value is mostly used for enabling unstable _values_ of + /// stable options. That separate check doesn't handle boolean values, so + /// to avoid an inconsistent state we also forbid them here. + #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")] + unstable_options: bool = (false, parse_no_value, [UNTRACKED], + "adds unstable command line options to rustc interface (default: no)"), + use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], + "use legacy .ctors section for initializers rather than .init_array"), + use_sync_unwind: Option = (None, parse_opt_bool, [TRACKED], + "Generate sync unwind tables instead of async unwind tables (default: no)"), + validate_mir: bool = (false, parse_bool, [UNTRACKED], + "validate MIR after each transformation"), + verbose_asm: bool = (false, parse_bool, [TRACKED], + "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"), + #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] + verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH], + "in general, enable more debug printouts (default: no)"), + #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")] + verify_llvm_ir: bool = (false, parse_bool, [TRACKED], + "verify LLVM IR (default: no)"), + virtual_function_elimination: bool = (false, parse_bool, [TRACKED], + "enables dead virtual function elimination optimization. \ + Requires `-Clto[=[fat,yes]]`"), + wasi_exec_model: Option = (None, parse_wasi_exec_model, [TRACKED], + "whether to build a wasi command or reactor"), + // This option only still exists to provide a more gradual transition path for people who need + // the spec-complaint C ABI to be used. + // FIXME remove this after a couple releases + wasm_c_abi: () = ((), parse_wasm_c_abi, [TRACKED], + "use spec-compliant C ABI for `wasm32-unknown-unknown` (deprecated, always enabled)"), + write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED], + "whether long type names should be written to files instead of being printed in errors"), + // tidy-alphabetical-end + + // If you add a new option, please update: + // - compiler/rustc_interface/src/tests.rs + // - src/doc/unstable-book/src/compiler-flags +} diff --git a/compiler/rustc_session/src/options/unstable.rs b/compiler/rustc_session/src/options/unstable.rs deleted file mode 100644 index dc00bd8a223af..0000000000000 --- a/compiler/rustc_session/src/options/unstable.rs +++ /dev/null @@ -1,585 +0,0 @@ -options! { - UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable", - - // If you add a new option, please update: - // - compiler/rustc_interface/src/tests.rs - // - src/doc/unstable-book/src/compiler-flags - - // tidy-alphabetical-start - allow_features: Option> = (None, parse_opt_comma_list, [TRACKED], - "only allow the listed language features to be enabled in code (comma separated)"), - always_encode_mir: bool = (false, parse_bool, [TRACKED], - "encode MIR of all functions into the crate metadata (default: no)"), - annotate_moves: AnnotateMoves = (AnnotateMoves::Disabled, parse_annotate_moves, [TRACKED], - "emit debug info for compiler-generated move and copy operations \ - to make them visible in profilers. Can be a boolean or a size limit in bytes (default: disabled)"), - assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], - "assert that the incremental cache is in given state: \ - either `loaded` or `not-loaded`."), - assume_incomplete_release: bool = (false, parse_bool, [TRACKED], - "make cfg(version) treat the current version as incomplete (default: no)"), - autodiff: Vec = (Vec::new(), parse_autodiff, [TRACKED], - "a list of autodiff flags to enable - Mandatory setting: - `=Enable` - Optional extra settings: - `=PrintTA` - `=PrintAA` - `=PrintPerf` - `=PrintSteps` - `=PrintModBefore` - `=PrintModAfter` - `=PrintModFinal` - `=PrintPasses`, - `=NoPostopt` - `=LooseTypes` - `=Inline` - Multiple options can be combined with commas."), - #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")] - binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], - "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ - (default: no)"), - box_noalias: bool = (true, parse_bool, [TRACKED], - "emit noalias metadata for box (default: yes)"), - branch_protection: Option = (None, parse_branch_protection, [TRACKED TARGET_MODIFIER], - "set options for branch target identification and pointer authentication on AArch64"), - build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED], - "whether the stable interface is being built"), - cache_proc_macros: bool = (false, parse_bool, [TRACKED], - "cache the results of derive proc macro invocations (potentially unsound!) (default: no"), - cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], - "instrument control-flow architecture protection"), - check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED], - "show all expected values in check-cfg diagnostics (default: no)"), - checksum_hash_algorithm: Option = (None, parse_cargo_src_file_hash, [TRACKED], - "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"), - codegen_backend: Option = (None, parse_opt_string, [TRACKED], - "the backend to use"), - codegen_source_order: bool = (false, parse_bool, [UNTRACKED], - "emit mono items in the order of spans in source files (default: no)"), - contract_checks: Option = (None, parse_opt_bool, [TRACKED], - "emit runtime checks for contract pre- and post-conditions (default: no)"), - coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED], - "control details of coverage instrumentation"), - crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], - "inject the given attribute in the crate"), - cross_crate_inline_threshold: InliningThreshold = (InliningThreshold::Sometimes(100), parse_inlining_threshold, [TRACKED], - "threshold to allow cross crate inlining of functions"), - debug_info_for_profiling: bool = (false, parse_bool, [TRACKED], - "emit discriminators and other data necessary for AutoFDO"), - debug_info_type_line_numbers: bool = (false, parse_bool, [TRACKED], - "emit type and line information for additional data types (default: no)"), - debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED], - "compress debug info sections (none, zlib, zstd, default: none)"), - deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], - "deduplicate identical diagnostics (default: yes)"), - default_visibility: Option = (None, parse_opt_symbol_visibility, [TRACKED], - "overrides the `default_visibility` setting of the target"), - dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], - "in dep-info output, omit targets for tracking dependencies of the dep-info files \ - themselves (default: no)"), - direct_access_external_data: Option = (None, parse_opt_bool, [TRACKED], - "Direct or use GOT indirect to reference external data symbols"), - dual_proc_macros: bool = (false, parse_bool, [TRACKED], - "load proc macros for both target and host, but only link to the target (default: no)"), - dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], - "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \ - (default: no)"), - dump_mir: Option = (None, parse_opt_string, [UNTRACKED], - "dump MIR state to file. - `val` is used to select which passes and functions to dump. For example: - `all` matches all passes and functions, - `foo` matches all passes for functions whose name contains 'foo', - `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo', - `foo | bar` all passes for function names containing 'foo' or 'bar'."), - dump_mir_dataflow: bool = (false, parse_bool, [UNTRACKED], - "in addition to `.mir` files, create graphviz `.dot` files with dataflow results \ - (default: no)"), - dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED], - "the directory the MIR is dumped into (default: `mir_dump`)"), - dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED], - "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"), - dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED], - "exclude the pass number when dumping MIR (used in tests) (default: no)"), - dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], - "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), - dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled, - parse_switch_with_opt_path, [UNTRACKED], - "output statistics about monomorphization collection"), - dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED], - "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"), - #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")] - dwarf_version: Option = (None, parse_opt_number, [TRACKED], - "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), - dylib_lto: bool = (false, parse_bool, [UNTRACKED], - "enables LTO for dylib crate type"), - eagerly_emit_delayed_bugs: bool = (false, parse_bool, [UNTRACKED], - "emit delayed bugs eagerly as errors instead of stashing them and emitting \ - them only if an error has not been emitted"), - ehcont_guard: bool = (false, parse_bool, [TRACKED], - "generate Windows EHCont Guard tables"), - embed_metadata: bool = (true, parse_bool, [TRACKED], - "embed metadata in rlibs and dylibs (default: yes)"), - embed_source: bool = (false, parse_bool, [TRACKED], - "embed source text in DWARF debug sections (default: no)"), - emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], - "emit a section containing stack size metadata (default: no)"), - emscripten_wasm_eh: bool = (true, parse_bool, [TRACKED], - "Use WebAssembly error handling for wasm32-unknown-emscripten"), - enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], - "enforce the type length limit when monomorphizing instances in codegen"), - experimental_default_bounds: bool = (false, parse_bool, [TRACKED], - "enable default bounds for experimental group of auto traits"), - export_executable_symbols: bool = (false, parse_bool, [TRACKED], - "export symbols from executables, as if they were dynamic libraries"), - external_clangrt: bool = (false, parse_bool, [UNTRACKED], - "rely on user specified linker commands to find clangrt"), - extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], - "turns on more checks to detect const UB, which can be slow (default: no)"), - #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")] - fewer_names: Option = (None, parse_opt_bool, [TRACKED], - "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ - (default: no)"), - fixed_x18: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], - "make the x18 register reserved on AArch64 (default: no)"), - flatten_format_args: bool = (true, parse_bool, [TRACKED], - "flatten nested format_args!() and literals into a simplified format_args!() call \ - (default: yes)"), - fmt_debug: FmtDebug = (FmtDebug::Full, parse_fmt_debug, [TRACKED], - "how detailed `#[derive(Debug)]` should be. `full` prints types recursively, \ - `shallow` prints only type names, `none` prints nothing and disables `{:?}`. (default: `full`)"), - force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], - "force all crates to be `rustc_private` unstable (default: no)"), - function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED], - "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"), - function_sections: Option = (None, parse_opt_bool, [TRACKED], - "whether each function should go in its own section"), - future_incompat_test: bool = (false, parse_bool, [UNTRACKED], - "forces all lints to be future incompatible, used for internal testing (default: no)"), - graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], - "use dark-themed colors in graphviz output (default: no)"), - graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], - "use the given `fontname` in graphviz output; can be overridden by setting \ - environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), - has_thread_local: Option = (None, parse_opt_bool, [TRACKED], - "explicitly enable the `cfg(target_thread_local)` directive"), - help: bool = (false, parse_no_value, [UNTRACKED], "Print unstable compiler options"), - higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED], - "allow deducing higher-ranked outlives assumptions from coroutines when proving auto traits"), - hint_mostly_unused: bool = (false, parse_bool, [TRACKED], - "hint that most of this crate will go unused, to minimize work for uncalled functions"), - human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], - "generate human-readable, predictable names for codegen units (default: no)"), - identify_regions: bool = (false, parse_bool, [UNTRACKED], - "display unnamed regions as `'`, using a non-ident unique id (default: no)"), - ignore_directory_in_diagnostics_source_blocks: Vec = (Vec::new(), parse_string_push, [UNTRACKED], - "do not display the source code block in diagnostics for files in the directory"), - incremental_ignore_spans: bool = (false, parse_bool, [TRACKED], - "ignore spans during ICH computation -- used for testing (default: no)"), - incremental_info: bool = (false, parse_bool, [UNTRACKED], - "print high-level information about incremental reuse (or the lack thereof) \ - (default: no)"), - incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], - "verify extended properties for incr. comp. (default: no): - - hashes of green query instances - - hash collisions of query keys - - hash collisions when creating dep-nodes"), - indirect_branch_cs_prefix: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], - "add `cs` prefix to `call` and `jmp` to indirect thunks (default: no)"), - inline_llvm: bool = (true, parse_bool, [TRACKED], - "enable LLVM inlining (default: yes)"), - inline_mir: Option = (None, parse_opt_bool, [TRACKED], - "enable MIR inlining (default: no)"), - inline_mir_forwarder_threshold: Option = (None, parse_opt_number, [TRACKED], - "inlining threshold when the caller is a simple forwarding function (default: 30)"), - inline_mir_hint_threshold: Option = (None, parse_opt_number, [TRACKED], - "inlining threshold for functions with inline hint (default: 100)"), - inline_mir_preserve_debug: Option = (None, parse_opt_bool, [TRACKED], - "when MIR inlining, whether to preserve debug info for callee variables \ - (default: preserve for debuginfo != None, otherwise remove)"), - inline_mir_threshold: Option = (None, parse_opt_number, [TRACKED], - "a default MIR inlining threshold (default: 50)"), - input_stats: bool = (false, parse_bool, [UNTRACKED], - "print some statistics about AST and HIR (default: no)"), - instrument_mcount: bool = (false, parse_bool, [TRACKED], - "insert function instrument code for mcount-based tracing (default: no)"), - instrument_xray: Option = (None, parse_instrument_xray, [TRACKED], - "insert function instrument code for XRay-based tracing (default: no) - Optional extra settings: - `=always` - `=never` - `=ignore-loops` - `=instruction-threshold=N` - `=skip-entry` - `=skip-exit` - Multiple options can be combined with commas."), - large_data_threshold: Option = (None, parse_opt_number, [TRACKED], - "set the threshold for objects to be stored in a \"large data\" section \ - (only effective with -Ccode-model=medium, default: 65536)"), - layout_seed: Option = (None, parse_opt_number, [TRACKED], - "seed layout randomization"), - link_directives: bool = (true, parse_bool, [TRACKED], - "honor #[link] directives in the compiled crate (default: yes)"), - link_native_libraries: bool = (true, parse_bool, [UNTRACKED], - "link native libraries in the linker invocation (default: yes)"), - link_only: bool = (false, parse_bool, [TRACKED], - "link the `.rlink` file generated by `-Z no-link` (default: no)"), - lint_llvm_ir: bool = (false, parse_bool, [TRACKED], - "lint LLVM IR (default: no)"), - lint_mir: bool = (false, parse_bool, [UNTRACKED], - "lint MIR before and after each transformation"), - llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED], - "a list of module flags to pass to LLVM (space separated)"), - llvm_plugins: Vec = (Vec::new(), parse_list, [TRACKED], - "a list LLVM plugins to enable (space separated)"), - llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], - "generate JSON tracing data file from LLVM data (default: no)"), - location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED], - "what location details should be tracked when using caller_location, either \ - `none`, or a comma separated list of location details, for which \ - valid options are `file`, `line`, and `column` (default: `file,line,column`)"), - ls: Vec = (Vec::new(), parse_list, [UNTRACKED], - "decode and print various parts of the crate metadata for a library crate \ - (space separated)"), - macro_backtrace: bool = (false, parse_bool, [UNTRACKED], - "show macro backtraces (default: no)"), - macro_stats: bool = (false, parse_bool, [UNTRACKED], - "print some statistics about macro expansions (default: no)"), - maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED], - "save as much information as possible about the correspondence between MIR and HIR \ - as source scopes (default: no)"), - merge_functions: Option = (None, parse_merge_functions, [TRACKED], - "control the operation of the MergeFunctions LLVM pass, taking \ - the same values as the target option of the same name"), - meta_stats: bool = (false, parse_bool, [UNTRACKED], - "gather metadata statistics (default: no)"), - metrics_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], - "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"), - min_function_alignment: Option = (None, parse_align, [TRACKED], - "align all functions to at least this many bytes. Must be a power of 2"), - min_recursion_limit: Option = (None, parse_opt_number, [TRACKED], - "set a minimum recursion limit (final limit = max(this, recursion_limit_from_crate))"), - mir_emit_retag: bool = (false, parse_bool, [TRACKED], - "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ - (default: no)"), - mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED], - "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \ - specified passes to be enabled, overriding all other checks. In particular, this will \ - enable unsound (known-buggy and hence usually disabled) passes without further warning! \ - Passes that are not specified are enabled or disabled by other flags as usual."), - mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED], - "include extra comments in mir pretty printing, like line numbers and statement indices, \ - details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"), - mir_opt_bisect_limit: Option = (None, parse_opt_number, [TRACKED], - "limit the number of MIR optimization pass executions (global across all bodies). \ - Pass executions after this limit are skipped and reported. (default: no limit)"), - #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] - mir_opt_level: Option = (None, parse_opt_number, [TRACKED], - "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), - mir_preserve_ub: bool = (false, parse_bool, [TRACKED], - "keep place mention statements and reads in trivial SwitchInt terminators, which are interpreted \ - e.g., by miri; implies -Zmir-opt-level=0 (default: no)"), - mir_strip_debuginfo: MirStripDebugInfo = (MirStripDebugInfo::None, parse_mir_strip_debuginfo, [TRACKED], - "Whether to remove some of the MIR debug info from methods. Default: None"), - move_size_limit: Option = (None, parse_opt_number, [TRACKED], - "the size at which the `large_assignments` lint starts to be emitted"), - mutable_noalias: bool = (true, parse_bool, [TRACKED], - "emit noalias metadata for mutable references (default: yes)"), - namespaced_crates: bool = (false, parse_bool, [TRACKED], - "allow crates to be namespaced by other crates (default: no)"), - next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED], - "enable and configure the next generation trait solver used by rustc"), - nll_facts: bool = (false, parse_bool, [UNTRACKED], - "dump facts from NLL analysis into side files (default: no)"), - nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED], - "the directory the NLL facts are dumped into (default: `nll-facts`)"), - no_analysis: bool = (false, parse_no_value, [UNTRACKED], - "parse and expand the source, but run no analysis"), - no_codegen: bool = (false, parse_no_value, [TRACKED_NO_CRATE_HASH], - "run all passes except codegen; no output"), - no_generate_arange_section: bool = (false, parse_no_value, [TRACKED], - "omit DWARF address ranges that give faster lookups"), - no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED], - "disable the compatibility version of the `implied_bounds_ty` query"), - no_leak_check: bool = (false, parse_no_value, [UNTRACKED], - "disable the 'leak check' for subtyping; unsound, but useful for tests"), - no_link: bool = (false, parse_no_value, [TRACKED], - "compile without linking"), - no_parallel_backend: bool = (false, parse_no_value, [UNTRACKED], - "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), - no_profiler_runtime: bool = (false, parse_no_value, [TRACKED], - "prevent automatic injection of the profiler_builtins crate"), - no_steal_thir: bool = (false, parse_bool, [UNTRACKED], - "don't steal the THIR when we're done with it; useful for rustc drivers (default: no)"), - no_trait_vptr: bool = (false, parse_no_value, [TRACKED], - "disable generation of trait vptr in vtable for upcasting"), - no_unique_section_names: bool = (false, parse_bool, [TRACKED], - "do not use unique names for text and data sections when -Z function-sections is used"), - normalize_docs: bool = (false, parse_bool, [TRACKED], - "normalize associated items in rustdoc when generating documentation"), - offload: Vec = (Vec::new(), parse_offload, [TRACKED], - "a list of offload flags to enable - Mandatory setting: - `=Enable` - Currently the only option available"), - on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED], - "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"), - osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], - "pass `-install_name @rpath/...` to the macOS linker (default: no)"), - packed_bundled_libs: bool = (false, parse_bool, [TRACKED], - "change rlib format to store native libraries as archives"), - panic_abort_tests: bool = (false, parse_bool, [TRACKED], - "support compiling tests with panic=abort (default: no)"), - panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED], - "panic strategy for panics in drops"), - parse_crate_root_only: bool = (false, parse_bool, [UNTRACKED], - "parse the crate root file only; do not parse other files, compile, assemble, or link \ - (default: no)"), - patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED], - "nop padding at function entry"), - plt: Option = (None, parse_opt_bool, [TRACKED], - "whether to use the PLT when calling into shared libraries; - only has effect for PIC code on systems with ELF binaries - (default: PLT is disabled if full relro is enabled on x86_64)"), - polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED], - "enable polonius-based borrow-checker (default: no)"), - pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED], - "a single extra argument to prepend the linker invocation (can be used several times)"), - pre_link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], - "extra arguments to prepend to the linker invocation (space separated)"), - precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED], - "use a more precise version of drop elaboration for matches on enums (default: yes). \ - This results in better codegen, but has caused miscompilations on some tier 2 platforms. \ - See #77382 and #74551."), - #[rustc_lint_opt_deny_field_access("use `Session::print_codegen_stats` instead of this field")] - print_codegen_stats: bool = (false, parse_bool, [UNTRACKED], - "print codegen statistics (default: no)"), - print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], - "print the LLVM optimization passes being run (default: no)"), - print_mono_items: bool = (false, parse_bool, [UNTRACKED], - "print the result of the monomorphization collection pass (default: no)"), - print_type_sizes: bool = (false, parse_bool, [UNTRACKED], - "print layout information for each type encountered (default: no)"), - proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], - "show backtraces for panics during proc-macro execution (default: no)"), - proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread, - parse_proc_macro_execution_strategy, [UNTRACKED], - "how to run proc-macro code (default: same-thread)"), - profile_closures: bool = (false, parse_no_value, [UNTRACKED], - "profile size of closures"), - profile_sample_use: Option = (None, parse_opt_pathbuf, [TRACKED], - "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), - profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], - "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"), - query_dep_graph: bool = (false, parse_bool, [UNTRACKED], - "enable queries of the dependency graph for regression testing (default: no)"), - randomize_layout: bool = (false, parse_bool, [TRACKED], - "randomize the layout of types (default: no)"), - reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], - "On x86-32 targets, it overrides the default ABI to return small structs in registers. - It is UNSOUND to link together crates that use different values for this flag!"), - regparm: Option = (None, parse_opt_number, [TRACKED TARGET_MODIFIER], - "On x86-32 targets, setting this to N causes the compiler to pass N arguments \ - in registers EAX, EDX, and ECX instead of on the stack for\ - \"C\", \"cdecl\", and \"stdcall\" fn.\ - It is UNSOUND to link together crates that use different values for this flag!"), - relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], - "whether ELF relocations can be relaxed"), - remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], - "remap paths under the current working directory to this path prefix"), - remark_dir: Option = (None, parse_opt_pathbuf, [UNTRACKED], - "directory into which to write optimization remarks (if not specified, they will be \ -written to standard error output)"), - retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], - "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"), - retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], - "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \ - target features (default: no)"), - #[rustc_lint_opt_deny_field_access("use `Session::sanitizers()` instead of this field")] - sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER], - "use a sanitizer"), - sanitizer_cfi_canonical_jump_tables: Option = (Some(true), parse_opt_bool, [TRACKED], - "enable canonical jump tables (default: yes)"), - sanitizer_cfi_generalize_pointers: Option = (None, parse_opt_bool, [TRACKED], - "enable generalizing pointer types (default: no)"), - sanitizer_cfi_normalize_integers: Option = (None, parse_opt_bool, [TRACKED TARGET_MODIFIER], - "enable normalizing integer types (default: no)"), - sanitizer_dataflow_abilist: Vec = (Vec::new(), parse_comma_list, [TRACKED], - "additional ABI list files that control how shadow parameters are passed (comma separated)"), - sanitizer_kcfi_arity: Option = (None, parse_opt_bool, [TRACKED], - "enable KCFI arity indicator (default: no)"), - sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED], - "enable origins tracking in MemorySanitizer"), - sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], - "enable recovery for selected sanitizers"), - saturating_float_casts: Option = (None, parse_opt_bool, [TRACKED], - "make float->int casts UB-free: numbers outside the integer type's range are clipped to \ - the max/min integer respectively, and NaN is mapped to 0 (default: yes)"), - self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled, - parse_switch_with_opt_path, [UNTRACKED], - "run the self profiler and output the raw event data"), - self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED], - "counter used by the self profiler (default: `wall-time`), one of: - `wall-time` (monotonic clock, i.e. `std::time::Instant`) - `instructions:u` (retired instructions, userspace-only) - `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)" - ), - /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs - self_profile_events: Option> = (None, parse_opt_comma_list, [UNTRACKED], - "specify the events recorded by the self profiler; - for example: `-Z self-profile-events=default,query-keys` - all options: none, all, default, generic-activity, query-provider, query-cache-hit - query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"), - share_generics: Option = (None, parse_opt_bool, [TRACKED], - "make the current crate share its generic instantiations"), - shell_argfiles: bool = (false, parse_bool, [UNTRACKED], - "allow argument files to be specified with POSIX \"shell-style\" argument quoting"), - simulate_remapped_rust_src_base: Option = (None, parse_opt_pathbuf, [TRACKED], - "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ - to rust's source base directory. only meant for testing purposes"), - small_data_threshold: Option = (None, parse_opt_number, [TRACKED], - "Set the threshold for objects to be stored in a \"small data\" section"), - span_debug: bool = (false, parse_bool, [UNTRACKED], - "forward proc_macro::Span's `Debug` impl to `Span`"), - /// o/w tests have closure@path - span_free_formats: bool = (false, parse_bool, [UNTRACKED], - "exclude spans when debug-printing compiler state (default: no)"), - split_dwarf_inlining: bool = (false, parse_bool, [TRACKED], - "provide minimal debug info in the object/executable to facilitate online \ - symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), - split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED], - "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) - (default: `split`) - - `split`: sections which do not require relocation are written into a DWARF object (`.dwo`) - file which is ignored by the linker - `single`: sections which do not require relocation are written into object file but ignored - by the linker"), - split_dwarf_out_dir : Option = (None, parse_opt_pathbuf, [TRACKED], - "location for writing split DWARF objects (`.dwo`) if enabled"), - split_lto_unit: Option = (None, parse_opt_bool, [TRACKED], - "enable LTO unit splitting (default: no)"), - src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], - "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), - #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] - stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], - "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), - staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED], - "allow staticlibs to have rust dylib dependencies"), - staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED], - "prefer dynamic linking to static linking for staticlibs (default: no)"), - strict_init_checks: bool = (false, parse_bool, [TRACKED], - "control if mem::uninitialized and mem::zeroed panic on more UB"), - #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")] - teach: bool = (false, parse_bool, [TRACKED], - "show extended diagnostic help (default: no)"), - temps_dir: Option = (None, parse_opt_string, [UNTRACKED], - "the directory the intermediate files are written to"), - terminal_urls: TerminalUrl = (TerminalUrl::No, parse_terminal_url, [UNTRACKED], - "use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output"), - #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] - thinlto: Option = (None, parse_opt_bool, [TRACKED], - "enable ThinLTO when possible"), - /// We default to 1 here since we want to behave like - /// a sequential compiler for now. This'll likely be adjusted - /// in the future. Note that -Zthreads=0 is the way to get - /// the num_cpus behavior. - #[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")] - threads: usize = (1, parse_threads, [UNTRACKED], - "use a thread pool with N threads"), - time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], - "measure time of each LLVM pass (default: no)"), - time_passes: bool = (false, parse_bool, [UNTRACKED], - "measure time of each rustc pass (default: no)"), - time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED], - "the format to use for -Z time-passes (`text` (default) or `json`)"), - tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED], - "sets a tiny, non-configurable limit for const eval; useful for compiler tests"), - #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")] - tls_model: Option = (None, parse_tls_model, [TRACKED], - "choose the TLS model to use (`rustc --print tls-models` for details)"), - trace_macros: bool = (false, parse_bool, [UNTRACKED], - "for every macro invocation, print its name and arguments (default: no)"), - track_diagnostics: bool = (false, parse_bool, [UNTRACKED], - "tracks where in rustc a diagnostic was emitted"), - translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED], - "translate remapped paths into local paths when possible (default: yes)"), - trap_unreachable: Option = (None, parse_opt_bool, [TRACKED], - "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), - treat_err_as_bug: Option> = (None, parse_treat_err_as_bug, [TRACKED], - "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \ - default if specified without a value: 1 - treat the first error as bug)"), - trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], - "in diagnostics, use heuristics to shorten paths referring to items"), - tune_cpu: Option = (None, parse_opt_string, [TRACKED], - "select processor to schedule for (`rustc --print target-cpus` for details)"), - #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_borrowck` instead of this field")] - typing_mode_borrowck: bool = (false, parse_bool, [TRACKED], - "enable `TypingMode::Borrowck`, changing the way opaque types are handled during MIR borrowck"), - #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] - ub_checks: Option = (None, parse_opt_bool, [TRACKED], - "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), - ui_testing: bool = (false, parse_bool, [UNTRACKED], - "emit compiler diagnostics in a form suitable for UI testing (default: no)"), - uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED], - "allow generating const initializers with mixed init/uninit chunks, \ - and set the maximum number of chunks for which this is allowed (default: 16)"), - unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED], - "take the brakes off const evaluation. NOTE: this is unsound (default: no)"), - unpretty: Option = (None, parse_unpretty, [UNTRACKED], - "present the input source, unstable (and less-pretty) variants; - `normal`, `identified`, - `expanded`, `expanded,identified`, - `expanded,hygiene` (with internal representations), - `ast-tree` (raw AST before expansion), - `ast-tree,expanded` (raw AST after expansion), - `hir` (the HIR), `hir,identified`, - `hir,typed` (HIR with types for each node), - `hir-tree` (dump the raw HIR), - `thir-tree`, `thir-flat`, - `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), - unsound_mir_opts: bool = (false, parse_bool, [TRACKED], - "enable unsound and buggy MIR optimizations (default: no)"), - /// This name is kind of confusing: Most unstable options enable something themselves, while - /// this just allows "normal" options to be feature-gated. - /// - /// The main check for `-Zunstable-options` takes place separately from the - /// usual parsing of `-Z` options (see [`crate::config::nightly_options`]), - /// so this boolean value is mostly used for enabling unstable _values_ of - /// stable options. That separate check doesn't handle boolean values, so - /// to avoid an inconsistent state we also forbid them here. - #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")] - unstable_options: bool = (false, parse_no_value, [UNTRACKED], - "adds unstable command line options to rustc interface (default: no)"), - use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], - "use legacy .ctors section for initializers rather than .init_array"), - use_sync_unwind: Option = (None, parse_opt_bool, [TRACKED], - "Generate sync unwind tables instead of async unwind tables (default: no)"), - validate_mir: bool = (false, parse_bool, [UNTRACKED], - "validate MIR after each transformation"), - verbose_asm: bool = (false, parse_bool, [TRACKED], - "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"), - #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] - verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH], - "in general, enable more debug printouts (default: no)"), - #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")] - verify_llvm_ir: bool = (false, parse_bool, [TRACKED], - "verify LLVM IR (default: no)"), - virtual_function_elimination: bool = (false, parse_bool, [TRACKED], - "enables dead virtual function elimination optimization. \ - Requires `-Clto[=[fat,yes]]`"), - wasi_exec_model: Option = (None, parse_wasi_exec_model, [TRACKED], - "whether to build a wasi command or reactor"), - // This option only still exists to provide a more gradual transition path for people who need - // the spec-complaint C ABI to be used. - // FIXME remove this after a couple releases - wasm_c_abi: () = ((), parse_wasm_c_abi, [TRACKED], - "use spec-compliant C ABI for `wasm32-unknown-unknown` (deprecated, always enabled)"), - write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED], - "whether long type names should be written to files instead of being printed in errors"), - // tidy-alphabetical-end - - // If you add a new option, please update: - // - compiler/rustc_interface/src/tests.rs - // - src/doc/unstable-book/src/compiler-flags -} diff --git a/src/tools/unstable-book-gen/Cargo.toml b/src/tools/unstable-book-gen/Cargo.toml index 12dd2eda3d9e2..73e5a91bec70a 100644 --- a/src/tools/unstable-book-gen/Cargo.toml +++ b/src/tools/unstable-book-gen/Cargo.toml @@ -6,8 +6,6 @@ edition = "2021" [dependencies] tidy = { path = "../tidy" } -proc-macro2 = { version = "1.0", features = ["span-locations"] } -syn = { version = "2.0", features = ["full", "parsing"] } # not actually needed but required for now to unify the feature selection of # `num-traits` between this and `rustbook` diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 21d4da46bef54..16550f83003dc 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -5,16 +5,11 @@ use std::env; use std::fs::{self, write}; use std::path::Path; -use proc_macro2::{Span, TokenStream, TokenTree}; -use syn::parse::{Parse, ParseStream}; -use syn::{Attribute, Ident, Item, LitStr, Token, parenthesized}; use tidy::diagnostics::RunningCheck; -use tidy::features::{ - Feature, Features, Status, collect_env_vars, collect_lang_features, collect_lib_features, -}; +use tidy::features::{Features, collect_env_vars, collect_lang_features, collect_lib_features}; use tidy::t; use tidy::unstable_book::{ - COMPILER_FLAGS_DIR, ENV_VARS_DIR, LANG_FEATURES_DIR, LIB_FEATURES_DIR, PATH_STR, + ENV_VARS_DIR, LANG_FEATURES_DIR, LIB_FEATURES_DIR, PATH_STR, collect_unstable_book_section_file_names, collect_unstable_feature_names, }; @@ -118,188 +113,6 @@ fn copy_recursive(from: &Path, to: &Path) { } } -fn collect_compiler_flags(compiler_path: &Path) -> Features { - let options_path = compiler_path.join("rustc_session/src/options/unstable.rs"); - let options_rs = t!(fs::read_to_string(&options_path), options_path); - parse_compiler_flags(&options_rs, &options_path) -} - -const DESCRIPTION_FIELD: usize = 3; -const REQUIRED_FIELDS: usize = 4; -const OPTIONAL_FIELDS: usize = 5; - -struct ParsedOptionEntry { - name: String, - line: usize, - description: String, -} - -struct UnstableOptionsInput { - struct_name: Ident, - entries: Vec, -} - -impl Parse for ParsedOptionEntry { - fn parse(input: ParseStream<'_>) -> syn::Result { - let _attrs = input.call(Attribute::parse_outer)?; - - let name: Ident = input.parse()?; - let line = name.span().start().line; - input.parse::()?; - let _ty: syn::Type = input.parse()?; - input.parse::()?; - - let tuple_content; - parenthesized!(tuple_content in input); - let tuple_tokens: TokenStream = tuple_content.parse()?; - let tuple_fields = split_tuple_fields(tuple_tokens); - - if !matches!(tuple_fields.len(), REQUIRED_FIELDS | OPTIONAL_FIELDS) { - return Err(syn::Error::new( - name.span(), - format!( - "unexpected field count for option `{name}`: expected {REQUIRED_FIELDS} or {OPTIONAL_FIELDS}, found {}", - tuple_fields.len() - ), - )); - } - - if tuple_fields.len() == OPTIONAL_FIELDS - && !is_deprecated_marker_field(&tuple_fields[REQUIRED_FIELDS]) - { - return Err(syn::Error::new( - name.span(), - format!( - "unexpected trailing field in option `{name}`: expected `is_deprecated_and_do_nothing: ...`" - ), - )); - } - - let description = parse_description_field(&tuple_fields[DESCRIPTION_FIELD], &name)?; - Ok(Self { name: name.to_string(), line, description }) - } -} - -impl Parse for UnstableOptionsInput { - fn parse(input: ParseStream<'_>) -> syn::Result { - let struct_name: Ident = input.parse()?; - input.parse::()?; - let _tmod_enum_name: Ident = input.parse()?; - input.parse::()?; - let _stat_name: Ident = input.parse()?; - input.parse::()?; - let _opt_module_name: Ident = input.parse()?; - input.parse::()?; - let _prefix: LitStr = input.parse()?; - input.parse::()?; - let _output_name: LitStr = input.parse()?; - input.parse::()?; - - let entries = - syn::punctuated::Punctuated::::parse_terminated(input)? - .into_iter() - .collect(); - - Ok(Self { struct_name, entries }) - } -} - -fn parse_compiler_flags(options_rs: &str, options_path: &Path) -> Features { - let options_input = parse_unstable_options_macro(options_rs).unwrap_or_else(|error| { - panic!("failed to parse unstable options from `{}`: {error}", options_path.display()) - }); - - let mut features = Features::new(); - for entry in options_input.entries { - if entry.name == "help" { - continue; - } - - features.insert( - entry.name, - Feature { - level: Status::Unstable, - since: None, - has_gate_test: false, - tracking_issue: None, - file: options_path.to_path_buf(), - line: entry.line, - description: Some(entry.description), - }, - ); - } - - features -} - -fn parse_unstable_options_macro(source: &str) -> syn::Result { - let ast = syn::parse_file(source)?; - - for item in ast.items { - let Item::Macro(item_macro) = item else { - continue; - }; - - if !item_macro.mac.path.is_ident("options") { - continue; - } - - let parsed = syn::parse2::(item_macro.mac.tokens)?; - if parsed.struct_name == "UnstableOptions" { - return Ok(parsed); - } - } - - Err(syn::Error::new( - Span::call_site(), - "could not find `options!` invocation for `UnstableOptions`", - )) -} - -fn parse_description_field(field: &TokenStream, option_name: &Ident) -> syn::Result { - let lit = syn::parse2::(field.clone()).map_err(|_| { - syn::Error::new_spanned( - field.clone(), - format!("expected description string literal in option `{option_name}`"), - ) - })?; - Ok(lit.value()) -} - -fn split_tuple_fields(tuple_tokens: TokenStream) -> Vec { - let mut fields = Vec::new(); - let mut current = TokenStream::new(); - - for token in tuple_tokens { - if let TokenTree::Punct(punct) = &token { - if punct.as_char() == ',' { - fields.push(current); - current = TokenStream::new(); - continue; - } - } - current.extend([token]); - } - fields.push(current); - - while matches!(fields.last(), Some(field) if field.is_empty()) { - fields.pop(); - } - - fields -} - -fn is_deprecated_marker_field(field: &TokenStream) -> bool { - let mut tokens = field.clone().into_iter(); - let Some(TokenTree::Ident(name)) = tokens.next() else { - return false; - }; - let Some(TokenTree::Punct(colon)) = tokens.next() else { - return false; - }; - name == "is_deprecated_and_do_nothing" && colon.as_char() == ':' -} - fn main() { let library_path_str = env::args_os().nth(1).expect("library/ path required"); let compiler_path_str = env::args_os().nth(2).expect("compiler/ path required"); @@ -316,7 +129,6 @@ fn main() { .filter(|&(ref name, _)| !lang_features.contains_key(name)) .collect(); let env_vars = collect_env_vars(compiler_path); - let compiler_flags = collect_compiler_flags(compiler_path); let doc_src_path = src_path.join(PATH_STR); @@ -332,17 +144,9 @@ fn main() { &dest_path.join(LIB_FEATURES_DIR), &lib_features, ); - generate_feature_files( - &doc_src_path.join(COMPILER_FLAGS_DIR), - &dest_path.join(COMPILER_FLAGS_DIR), - &compiler_flags, - ); generate_env_files(&doc_src_path.join(ENV_VARS_DIR), &dest_path.join(ENV_VARS_DIR), &env_vars); copy_recursive(&doc_src_path, &dest_path); generate_summary(&dest_path, &lang_features, &lib_features); } - -#[cfg(test)] -mod tests; diff --git a/src/tools/unstable-book-gen/src/tests.rs b/src/tools/unstable-book-gen/src/tests.rs deleted file mode 100644 index 000cfaebdac30..0000000000000 --- a/src/tools/unstable-book-gen/src/tests.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::path::{Path, PathBuf}; - -use super::parse_compiler_flags; - -#[test] -fn parses_unstable_options_entries() { - let options_rs = r#"options! { - UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable", - - #[rustc_lint_opt_deny_field_access("test attr")] - allow_features: Option> = (None, parse_opt_comma_list, [TRACKED], - "only allow the listed language features to be enabled in code (comma separated)"), - dump_mir: Option = (None, parse_opt_string, [UNTRACKED], - "dump MIR state to file.\n\ - `val` is used to select which passes and functions to dump."), - join_lines: bool = (false, parse_bool, [TRACKED], - "join \ - continued lines"), - help: bool = (false, parse_no_value, [UNTRACKED], "Print unstable compiler options"), -}"#; - - let features = parse_compiler_flags(options_rs, Path::new("options/unstable.rs")); - - assert!(features.contains_key("allow_features")); - assert!(features.contains_key("dump_mir")); - assert!(features.contains_key("join_lines")); - assert!(!features.contains_key("help")); - - assert!( - features["dump_mir"] - .description - .as_deref() - .expect("dump_mir description should exist") - .starts_with("dump MIR state to file.\n"), - ); - assert_eq!(features["join_lines"].description.as_deref(), Some("join continued lines")); - assert_eq!( - features["allow_features"].description.as_deref(), - Some("only allow the listed language features to be enabled in code (comma separated)"), - ); - assert_eq!(features["allow_features"].file, PathBuf::from("options/unstable.rs")); - assert_eq!(features["allow_features"].line, 5); -} - -#[test] -fn parser_accepts_optional_trailing_metadata() { - let options_rs = r##"options! { - UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable", - - deprecated_flag: bool = (false, parse_no_value, [UNTRACKED], "deprecated flag", - is_deprecated_and_do_nothing: true), - raw_description: bool = (false, parse_no_value, [UNTRACKED], r#"raw "quoted" text"#), -}"##; - - let features = parse_compiler_flags(options_rs, Path::new("options/unstable.rs")); - assert_eq!(features["deprecated_flag"].description.as_deref(), Some("deprecated flag")); - assert_eq!(features["raw_description"].description.as_deref(), Some("raw \"quoted\" text"),); -} - -#[test] -fn parses_real_unstable_options_file() { - let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); - let options_path = manifest_dir.join("../../../compiler/rustc_session/src/options/unstable.rs"); - let options_rs = std::fs::read_to_string(&options_path).unwrap(); - let features = parse_compiler_flags(&options_rs, &options_path); - - assert!(features.contains_key("allow_features")); - assert!(features.contains_key("dump_mir")); - assert!(features.contains_key("unstable_options")); - assert!(!features.contains_key("help")); - assert!(features["dump_mir"].line > 0); - assert!(features["dump_mir"].description.as_deref().unwrap().starts_with("dump MIR state")); -}