From 4c947984d64ae63a71c5441082a35309b9198fbf Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 9 Jul 2025 13:42:18 -0700 Subject: [PATCH 01/25] random: Add comment on `RandomSource::fill_bytes` about multiple calls This allows efficient implementations for random sources that generate a word at a time. --- library/core/src/random.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/core/src/random.rs b/library/core/src/random.rs index 051fe26086389..40338c3f4ac70 100644 --- a/library/core/src/random.rs +++ b/library/core/src/random.rs @@ -7,6 +7,11 @@ #[unstable(feature = "random", issue = "130703")] pub trait RandomSource { /// Fills `bytes` with random bytes. + /// + /// Note that calling `fill_bytes` multiple times is not equivalent to calling `fill_bytes` once + /// with a larger buffer. A `RandomSource` is allowed to return different bytes for those two + /// cases. For instance, this allows a `RandomSource` to generate a word at a time and throw + /// part of it away if not needed. fn fill_bytes(&mut self, bytes: &mut [u8]); } From 8d0e0c6d6fae36283c11535dcb88b52baf286fc5 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Tue, 8 Jul 2025 10:47:01 +0200 Subject: [PATCH 02/25] interpret/allocation: expose init + write_wildcards on a range --- .../rustc_const_eval/src/interpret/memory.rs | 2 +- .../src/mir/interpret/allocation.rs | 33 +++++++++---------- .../interpret/allocation/provenance_map.rs | 28 ++++++++++++---- src/tools/miri/src/shims/native_lib/mod.rs | 7 ++-- 4 files changed, 42 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 524023b8104b5..6053534266f95 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1472,7 +1472,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest_alloc .write_uninit(&tcx, dest_range) .map_err(|e| e.to_interp_error(dest_alloc_id))?; - // We can forget about the provenance, this is all not initialized anyway. + // `write_uninit` also resets the provenance, so we are done. return interp_ok(()); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index f039849d1bbc8..133111ff15de8 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -101,6 +101,8 @@ pub struct Allocation, /// Denotes which part of this allocation is initialized. + /// + /// Invariant: the uninitialized parts have no provenance. init_mask: InitMask, /// The alignment of the allocation to detect unaligned reads. /// (`Align` guarantees that this is a power of two.) @@ -796,24 +798,19 @@ impl Allocation Ok(()) } - /// Initialize all previously uninitialized bytes in the entire allocation, and set - /// provenance of everything to `Wildcard`. Before calling this, make sure all - /// provenance in this allocation is exposed! - pub fn prepare_for_native_access(&mut self) { - let full_range = AllocRange { start: Size::ZERO, size: Size::from_bytes(self.len()) }; - // Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be. - for chunk in self.init_mask.range_as_init_chunks(full_range) { - if !chunk.is_init() { - let uninit_bytes = &mut self.bytes - [chunk.range().start.bytes_usize()..chunk.range().end.bytes_usize()]; - uninit_bytes.fill(0); - } - } - // Mark everything as initialized now. - self.mark_init(full_range, true); - - // Set provenance of all bytes to wildcard. - self.provenance.write_wildcards(self.len()); + /// Mark all bytes in the given range as initialised and reset the provenance + /// to wildcards. This entirely breaks the normal mechanisms for tracking + /// initialisation and is only provided for Miri operating in native-lib + /// mode. UB will be missed if the underlying bytes were not actually written to. + /// + /// If `range` is `None`, defaults to performing this on the whole allocation. + pub fn process_native_write(&mut self, cx: &impl HasDataLayout, range: Option) { + let range = range.unwrap_or_else(|| AllocRange { + start: Size::ZERO, + size: Size::from_bytes(self.len()), + }); + self.mark_init(range, true); + self.provenance.write_wildcards(cx, range); } /// Remove all provenance in the given memory range. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 9c6e16643869b..119d4be64e6a1 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -212,21 +212,37 @@ impl ProvenanceMap { Ok(()) } - /// Overwrites all provenance in the allocation with wildcard provenance. + /// Overwrites all provenance in the given range with wildcard provenance. + /// Pointers partially overwritten will have their provenances preserved + /// bytewise on their remaining bytes. /// /// Provided for usage in Miri and panics otherwise. - pub fn write_wildcards(&mut self, alloc_size: usize) { + pub fn write_wildcards(&mut self, cx: &impl HasDataLayout, range: AllocRange) { assert!( Prov::OFFSET_IS_ADDR, "writing wildcard provenance is not supported when `OFFSET_IS_ADDR` is false" ); let wildcard = Prov::WILDCARD.unwrap(); - // Remove all pointer provenances, then write wildcards into the whole byte range. - self.ptrs.clear(); - let last = Size::from_bytes(alloc_size); let bytes = self.bytes.get_or_insert_with(Box::default); - for offset in Size::ZERO..last { + + // Remove pointer provenances that overlap with the range, then readd the edge ones bytewise. + let ptr_range = Self::adjusted_range_ptrs(range, cx); + let ptrs = self.ptrs.range(ptr_range.clone()); + if let Some((offset, prov)) = ptrs.first() { + for byte_ofs in *offset..range.start { + bytes.insert(byte_ofs, *prov); + } + } + if let Some((offset, prov)) = ptrs.last() { + for byte_ofs in range.end()..*offset + cx.data_layout().pointer_size() { + bytes.insert(byte_ofs, *prov); + } + } + self.ptrs.remove_range(ptr_range); + + // Overwrite bytewise provenance. + for offset in range.start..range.end() { bytes.insert(offset, wildcard); } } diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 9b30d8ce78bf8..02c3bde036d48 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -231,7 +231,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .collect::>>(); // Prepare all exposed memory (both previously exposed, and just newly exposed since a - // pointer was passed as argument). + // pointer was passed as argument). Uninitialised memory is left as-is, but any data + // exposed this way is garbage anyway. this.visit_reachable_allocs(this.exposed_allocs(), |this, alloc_id, info| { // If there is no data behind this pointer, skip this. if !matches!(info.kind, AllocKind::LiveData) { @@ -251,8 +252,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Prepare for possible write from native code if mutable. if info.mutbl.is_mut() { - let alloc = &mut this.get_alloc_raw_mut(alloc_id)?.0; - alloc.prepare_for_native_access(); + let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?; + alloc.process_native_write(&cx.tcx, None); // Also expose *mutable* provenance for the interpreter-level allocation. std::hint::black_box(alloc.get_bytes_unchecked_raw_mut().expose_provenance()); } From e681d1a9731897951ea4c2d68c7d8f4a322b9904 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 08:17:58 +0000 Subject: [PATCH 03/25] constify `From` and `Into` --- library/core/src/convert/mod.rs | 29 +++++++++++++----- tests/ui/specialization/issue-111232.rs | 9 ++++++ tests/ui/specialization/issue-111232.stderr | 9 ++++-- .../non-const-op-in-closure-in-const.rs | 4 +-- .../non-const-op-in-closure-in-const.stderr | 30 ------------------- 5 files changed, 38 insertions(+), 43 deletions(-) delete mode 100644 tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 7132e712ec52f..38381dbdf2303 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -445,6 +445,8 @@ pub trait AsMut: PointeeSized { #[rustc_diagnostic_item = "Into"] #[stable(feature = "rust1", since = "1.0.0")] #[doc(search_unbox)] +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[const_trait] pub trait Into: Sized { /// Converts this type into the (usually inferred) input type. #[must_use] @@ -580,6 +582,8 @@ pub trait Into: Sized { note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ))] #[doc(search_unbox)] +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[const_trait] pub trait From: Sized { /// Converts to this type from the input type. #[rustc_diagnostic_item = "from_fn"] @@ -607,6 +611,8 @@ pub trait From: Sized { /// [`Into`], see there for details. #[rustc_diagnostic_item = "TryInto"] #[stable(feature = "try_from", since = "1.34.0")] +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[const_trait] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. #[stable(feature = "try_from", since = "1.34.0")] @@ -685,6 +691,8 @@ pub trait TryInto: Sized { /// [`try_from`]: TryFrom::try_from #[rustc_diagnostic_item = "TryFrom"] #[stable(feature = "try_from", since = "1.34.0")] +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +#[const_trait] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. #[stable(feature = "try_from", since = "1.34.0")] @@ -754,9 +762,10 @@ where // From implies Into #[stable(feature = "rust1", since = "1.0.0")] -impl Into for T +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +impl const Into for T where - U: From, + U: ~const From, { /// Calls `U::from(self)`. /// @@ -771,7 +780,8 @@ where // From (and thus Into) is reflexive #[stable(feature = "rust1", since = "1.0.0")] -impl From for T { +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +impl const From for T { /// Returns the argument unchanged. #[inline(always)] fn from(t: T) -> T { @@ -787,7 +797,8 @@ impl From for T { #[stable(feature = "convert_infallible", since = "1.34.0")] #[rustc_reservation_impl = "permitting this impl would forbid us from adding \ `impl From for T` later; see rust-lang/rust#64715 for details"] -impl From for T { +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +impl const From for T { fn from(t: !) -> T { t } @@ -795,9 +806,10 @@ impl From for T { // TryFrom implies TryInto #[stable(feature = "try_from", since = "1.34.0")] -impl TryInto for T +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +impl const TryInto for T where - U: TryFrom, + U: ~const TryFrom, { type Error = U::Error; @@ -810,9 +822,10 @@ where // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. #[stable(feature = "try_from", since = "1.34.0")] -impl TryFrom for T +#[rustc_const_unstable(feature = "const_from", issue = "143773")] +impl const TryFrom for T where - U: Into, + U: ~const Into, { type Error = Infallible; diff --git a/tests/ui/specialization/issue-111232.rs b/tests/ui/specialization/issue-111232.rs index 3ed3c580e6d12..fa00f01886fb5 100644 --- a/tests/ui/specialization/issue-111232.rs +++ b/tests/ui/specialization/issue-111232.rs @@ -1,4 +1,13 @@ #![feature(min_specialization)] +#![feature(const_trait_impl)] + +trait From { + fn from(t: T) -> Self; +} + +impl From for T { + fn from(t: T) -> T { t } +} struct S; diff --git a/tests/ui/specialization/issue-111232.stderr b/tests/ui/specialization/issue-111232.stderr index ed392e4f9152b..5f169f0bb36c5 100644 --- a/tests/ui/specialization/issue-111232.stderr +++ b/tests/ui/specialization/issue-111232.stderr @@ -1,10 +1,13 @@ error[E0520]: `from` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/issue-111232.rs:6:5 + --> $DIR/issue-111232.rs:15:5 | +LL | impl From for T { + | --------------------- parent `impl` is here +... LL | fn from(s: S) -> S { - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ cannot specialize default item `from` | - = note: parent implementation is in crate `core` + = note: to specialize, `from` in the parent `impl` must be marked `default` error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs index 86e3e5f769f8a..d5f80acc15b54 100644 --- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs +++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.rs @@ -1,6 +1,6 @@ -//@ known-bug: #110395 +#![feature(const_trait_impl, const_from)] -#![feature(const_trait_impl)] +//@ check-pass #[const_trait] trait Convert { diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr deleted file mode 100644 index e7f10e73c6924..0000000000000 --- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/non-const-op-in-closure-in-const.rs:10:44 - | -LL | impl const Convert for A where B: [const] From { - | ^^^^^^^ can't be applied to `From` - | -note: `From` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/convert/mod.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/non-const-op-in-closure-in-const.rs:10:44 - | -LL | impl const Convert for A where B: [const] From { - | ^^^^^^^ can't be applied to `From` - | -note: `From` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/convert/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const associated function `>::from` in constant functions - --> $DIR/non-const-op-in-closure-in-const.rs:12:9 - | -LL | B::from(self) - | ^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0015`. From 074846289a4f69d8057bc3ee7789728f560e1ec8 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Fri, 11 Jul 2025 17:31:08 +0800 Subject: [PATCH 04/25] std: move NuttX to use arc4random for random number generation * Move `target_os = "nuttx"` from unix_legacy to arc4random section * This aligns NuttX with other POSIX-compliant systems that support arc4random * Improves random number generation quality on NuttX by using the system's built-in arc4random implementation instead of legacy fallback methods NuttX supports arc4random_buf which provides better entropy and security compared to the legacy random number generation methods. Signed-off-by: Huang Qi --- library/std/src/sys/random/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index 013e886a99b6b..fc85797dcc269 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -20,6 +20,7 @@ cfg_if::cfg_if! { target_os = "rtems", target_os = "solaris", target_os = "vita", + target_os = "nuttx", ))] { mod arc4random; pub use arc4random::fill_bytes; @@ -44,7 +45,6 @@ cfg_if::cfg_if! { target_os = "hurd", target_os = "l4re", target_os = "nto", - target_os = "nuttx", ))] { mod unix_legacy; pub use unix_legacy::fill_bytes; From 7ad30cc619b4c0b7b2b9f30fd8f0c20ab053cb16 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 09:55:05 +0000 Subject: [PATCH 05/25] Some const_trait_impl test cleanups --- tests/ui/traits/const-traits/const-drop.rs | 2 -- tests/ui/traits/const-traits/issue-102985.rs | 5 +---- tests/ui/traits/const-traits/issue-102985.stderr | 2 +- tests/ui/traits/const-traits/issue-88155.rs | 5 +---- tests/ui/traits/const-traits/issue-88155.stderr | 2 +- 5 files changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/ui/traits/const-traits/const-drop.rs b/tests/ui/traits/const-traits/const-drop.rs index 5df3a77f73ab6..dc985a8f62073 100644 --- a/tests/ui/traits/const-traits/const-drop.rs +++ b/tests/ui/traits/const-traits/const-drop.rs @@ -17,12 +17,10 @@ impl<'a> const Drop for S<'a> { } const fn a(_: T) {} -//FIXME ~^ ERROR destructor of const fn b() -> u8 { let mut c = 0; let _ = S(&mut c); - //FIXME ~^ ERROR destructor of a(S(&mut c)); c } diff --git a/tests/ui/traits/const-traits/issue-102985.rs b/tests/ui/traits/const-traits/issue-102985.rs index e5394ddd688e3..ebab6566d4b57 100644 --- a/tests/ui/traits/const-traits/issue-102985.rs +++ b/tests/ui/traits/const-traits/issue-102985.rs @@ -1,12 +1,9 @@ -//@ known-bug: #110395 #![feature(const_trait_impl)] struct Bug { inner: [(); match || 1 { n => n(), - //FIXME ~^ ERROR the trait bound - //FIXME ~| ERROR the trait bound - //FIXME ~| ERROR cannot call non-const closure in constants + //~^ ERROR cannot call non-const closure in constants }], } diff --git a/tests/ui/traits/const-traits/issue-102985.stderr b/tests/ui/traits/const-traits/issue-102985.stderr index 7c5c5acf20799..8588dc17e7012 100644 --- a/tests/ui/traits/const-traits/issue-102985.stderr +++ b/tests/ui/traits/const-traits/issue-102985.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const closure in constants - --> $DIR/issue-102985.rs:6:14 + --> $DIR/issue-102985.rs:5:14 | LL | n => n(), | ^^^ diff --git a/tests/ui/traits/const-traits/issue-88155.rs b/tests/ui/traits/const-traits/issue-88155.rs index a26128a6ecc23..a642e1101c7b2 100644 --- a/tests/ui/traits/const-traits/issue-88155.rs +++ b/tests/ui/traits/const-traits/issue-88155.rs @@ -1,5 +1,3 @@ -//@ known-bug: #110395 - #![feature(const_trait_impl)] pub trait A { @@ -8,8 +6,7 @@ pub trait A { pub const fn foo() -> bool { T::assoc() - //FIXME ~^ ERROR the trait bound - //FIXME ~| ERROR cannot call non-const function + //~^ ERROR cannot call non-const associated function } fn main() {} diff --git a/tests/ui/traits/const-traits/issue-88155.stderr b/tests/ui/traits/const-traits/issue-88155.stderr index 2e140ac9ff6b6..96a3c4187f5c2 100644 --- a/tests/ui/traits/const-traits/issue-88155.stderr +++ b/tests/ui/traits/const-traits/issue-88155.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const associated function `::assoc` in constant functions - --> $DIR/issue-88155.rs:10:5 + --> $DIR/issue-88155.rs:8:5 | LL | T::assoc() | ^^^^^^^^^^ From 120c9fcb86bfde65b562ba4e957ef7003108d6ae Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 11 Jul 2025 19:58:22 +0800 Subject: [PATCH 06/25] Disambiguate between rustc vs std having debug assertions Additionally, `NO_DEBUG_ASSERTIONS` is set by CI that threads through to the `./configure` script, which is somewhat fragile and "spooky action at a distance". Instead, use env vars controlled by compiletest, whose debug assertion info comes from bootstrap. --- src/tools/compiletest/src/runtest/run_make.rs | 13 +++++++++++++ src/tools/run-make-support/src/env.rs | 15 ++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 60e8e16e25eff..c8d5190c03908 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -225,6 +225,19 @@ impl TestCx<'_> { cmd.env("RUNNER", runner); } + // Guard against externally-set env vars. + cmd.env_remove("__RUSTC_DEBUG_ASSERTIONS_ENABLED"); + if self.config.with_rustc_debug_assertions { + // Used for `run_make_support::env::rustc_debug_assertions_enabled`. + cmd.env("__RUSTC_DEBUG_ASSERTIONS_ENABLED", "1"); + } + + cmd.env_remove("__STD_DEBUG_ASSERTIONS_ENABLED"); + if self.config.with_std_debug_assertions { + // Used for `run_make_support::env::std_debug_assertions_enabled`. + cmd.env("__STD_DEBUG_ASSERTIONS_ENABLED", "1"); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs index 9acbb16d73e76..cf1a6f7351a7f 100644 --- a/src/tools/run-make-support/src/env.rs +++ b/src/tools/run-make-support/src/env.rs @@ -18,11 +18,20 @@ pub fn env_var_os(name: &str) -> OsString { } } -/// Check if `NO_DEBUG_ASSERTIONS` is set (usually this may be set in CI jobs). +/// Check if staged `rustc`-under-test was built with debug assertions. #[track_caller] #[must_use] -pub fn no_debug_assertions() -> bool { - std::env::var_os("NO_DEBUG_ASSERTIONS").is_some() +pub fn rustc_debug_assertions_enabled() -> bool { + // Note: we assume this env var is set when the test recipe is being executed. + std::env::var_os("__RUSTC_DEBUG_ASSERTIONS_ENABLED").is_some() +} + +/// Check if staged `std`-under-test was built with debug assertions. +#[track_caller] +#[must_use] +pub fn std_debug_assertions_enabled() -> bool { + // Note: we assume this env var is set when the test recipe is being executed. + std::env::var_os("__STD_DEBUG_ASSERTIONS_ENABLED").is_some() } /// A wrapper around [`std::env::set_current_dir`] which includes the directory From 33e69623bae7cee0e1706cc64f81edee8a4283d9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 11 Jul 2025 20:01:42 +0800 Subject: [PATCH 07/25] Fix std debug assertions gate in `fmt-write-boat` The test itself is still broken, but fix this gating separately first. --- tests/run-make/fmt-write-bloat/rmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs index 3348651d501fd..af6ff6c298331 100644 --- a/tests/run-make/fmt-write-bloat/rmake.rs +++ b/tests/run-make/fmt-write-bloat/rmake.rs @@ -18,7 +18,7 @@ //@ ignore-cross-compile use run_make_support::artifact_names::bin_name; -use run_make_support::env::no_debug_assertions; +use run_make_support::env::std_debug_assertions_enabled; use run_make_support::rustc; use run_make_support::symbols::any_symbol_contains; @@ -26,7 +26,7 @@ fn main() { rustc().input("main.rs").opt().run(); // panic machinery identifiers, these should not appear in the final binary let mut panic_syms = vec!["panic_bounds_check", "Debug"]; - if no_debug_assertions() { + if std_debug_assertions_enabled() { // if debug assertions are allowed, we need to allow these, // otherwise, add them to the list of symbols to deny. panic_syms.extend_from_slice(&["panicking", "panic_fmt", "pad_integral", "Display"]); From 1a28fb8b7b06b25834ef8fb4295cdd2ade1f6da7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 11 Jul 2025 15:51:42 +0200 Subject: [PATCH 08/25] Update sysinfo version to `0.36.0` --- Cargo.lock | 4 ++-- src/bootstrap/Cargo.lock | 8 ++++---- src/bootstrap/Cargo.toml | 2 +- src/tools/opt-dist/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 271a2f7962cac..65718ce44338e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5230,9 +5230,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.35.2" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e" +checksum = "aab138f5c1bb35231de19049060a87977ad23e04f2303e953bc5c2947ac7dec4" dependencies = [ "libc", "objc2-core-foundation", diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 2434a278d556b..e091c94eb53aa 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -386,9 +386,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libredox" @@ -730,9 +730,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422" +checksum = "aab138f5c1bb35231de19049060a87977ad23e04f2303e953bc5c2947ac7dec4" dependencies = [ "libc", "memchr", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 073cebdcae24f..8dc41d1dec697 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -58,7 +58,7 @@ walkdir = "2.4" xz2 = "0.1" # Dependencies needed by the build-metrics feature -sysinfo = { version = "0.35.0", default-features = false, optional = true, features = ["system"] } +sysinfo = { version = "0.36.0", default-features = false, optional = true, features = ["system"] } # Dependencies needed by the `tracing` feature tracing = { version = "0.1", optional = true, features = ["attributes"] } diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index dfa884bc3f771..2ed3fbac709ea 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -10,7 +10,7 @@ log = "0.4" anyhow = "1" humantime = "2" humansize = "2" -sysinfo = { version = "0.35.0", default-features = false, features = ["disk"] } +sysinfo = { version = "0.36.0", default-features = false, features = ["disk"] } fs_extra = "1" camino = "1" tar = "0.4" From 2f05fa6fffb857c08edd0af2dc69f05fa1f02703 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 11 Jul 2025 17:02:24 +0200 Subject: [PATCH 09/25] Fix ICE for parsed attributes with longer path not handled by CheckAttrVisitor Signed-off-by: Jonathan Brouwer --- Cargo.lock | 1 + compiler/rustc_attr_parsing/src/context.rs | 5 +++++ compiler/rustc_passes/Cargo.toml | 1 + compiler/rustc_passes/src/check_attr.rs | 11 ++++++++++- tests/ui/attributes/builtin-attribute-prefix.rs | 8 ++++++++ .../ui/attributes/builtin-attribute-prefix.stderr | 15 +++++++++++++++ 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/ui/attributes/builtin-attribute-prefix.rs create mode 100644 tests/ui/attributes/builtin-attribute-prefix.stderr diff --git a/Cargo.lock b/Cargo.lock index 271a2f7962cac..98a78b8495bcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4349,6 +4349,7 @@ dependencies = [ "rustc_ast_lowering", "rustc_ast_pretty", "rustc_attr_data_structures", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_expand", diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index dbe1a5b2ad03d..737fe6ba0817f 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -718,6 +718,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes } + /// Returns whether there is a parser for an attribute with this name + pub fn is_parsed_attribute(path: &[Symbol]) -> bool { + Late::parsers().0.contains_key(path) + } + fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { match args { ast::AttrArgs::Empty => AttrArgs::Empty, diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index b91674890765a..503fc98da76dd 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -10,6 +10,7 @@ rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 0aa6a2b41cfb6..3a22b19683cb7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -7,10 +7,12 @@ use std::cell::Cell; use std::collections::hash_map::Entry; +use std::slice; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; +use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -373,11 +375,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::custom_mir, .. ] => {} - [name, ..] => { + [name, rest@..] => { match BUILTIN_ATTRIBUTE_MAP.get(name) { // checked below Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} Some(_) => { + if rest.len() > 0 && AttributeParser::::is_parsed_attribute(slice::from_ref(name)) { + // Check if we tried to use a builtin attribute as an attribute namespace, like `#[must_use::skip]`. + // This check is here to solve https://github.com/rust-lang/rust/issues/137590 + // An error is already produced for this case elsewhere + continue + } + // FIXME: differentiate between unstable and internal attributes just // like we do with features instead of just accepting `rustc_` // attributes by name. That should allow trimming the above list, too. diff --git a/tests/ui/attributes/builtin-attribute-prefix.rs b/tests/ui/attributes/builtin-attribute-prefix.rs new file mode 100644 index 0000000000000..d184c6d008df6 --- /dev/null +++ b/tests/ui/attributes/builtin-attribute-prefix.rs @@ -0,0 +1,8 @@ +// Regression test for https://github.com/rust-lang/rust/issues/143789 +#[must_use::skip] +//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `must_use` +fn main() { } + +// Regression test for https://github.com/rust-lang/rust/issues/137590 +struct S(#[stable::skip] u8, u16, u32); +//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `stable` diff --git a/tests/ui/attributes/builtin-attribute-prefix.stderr b/tests/ui/attributes/builtin-attribute-prefix.stderr new file mode 100644 index 0000000000000..a16080c003fb4 --- /dev/null +++ b/tests/ui/attributes/builtin-attribute-prefix.stderr @@ -0,0 +1,15 @@ +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `stable` + --> $DIR/builtin-attribute-prefix.rs:7:12 + | +LL | struct S(#[stable::skip] u8, u16, u32); + | ^^^^^^ use of unresolved module or unlinked crate `stable` + +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `must_use` + --> $DIR/builtin-attribute-prefix.rs:2:3 + | +LL | #[must_use::skip] + | ^^^^^^^^ use of unresolved module or unlinked crate `must_use` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. From cdbe44d8069d2f352c6dea560574a6fa9d9df5ae Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 11 Jul 2025 20:33:36 +0530 Subject: [PATCH 10/25] Use short command method directly from fingerprint --- src/bootstrap/src/utils/tracing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/tracing.rs b/src/bootstrap/src/utils/tracing.rs index 99849341dc3b9..58d127dfb791d 100644 --- a/src/bootstrap/src/utils/tracing.rs +++ b/src/bootstrap/src/utils/tracing.rs @@ -58,7 +58,7 @@ macro_rules! trace_cmd { target: "COMMAND", ::tracing::Level::TRACE, "executing command", - cmd = $cmd.format_short_cmd(), + cmd = $cmd.fingerprint().format_short_cmd(), full_cmd = ?$cmd ).entered() } From 0c81bf80e031ec000ddaab1578cc39a40364a54d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Jul 2025 17:35:57 +0200 Subject: [PATCH 11/25] fix PartialEq const feature name and const_cmp tracking issue --- library/core/src/cmp.rs | 12 ++++++------ tests/ui/const-generics/issues/issue-90318.rs | 2 +- tests/ui/consts/const_cmp_type_id.rs | 2 +- tests/ui/consts/const_transmute_type_id.rs | 2 +- tests/ui/consts/const_transmute_type_id2.rs | 2 +- tests/ui/consts/const_transmute_type_id3.rs | 2 +- tests/ui/consts/const_transmute_type_id4.rs | 2 +- tests/ui/consts/issue-73976-monomorphic.rs | 1 + tests/ui/consts/issue-90870.rs | 6 +++--- tests/ui/consts/issue-90870.stderr | 12 ++++++------ .../const-traits/call-const-trait-method-pass.rs | 2 +- tests/ui/traits/const-traits/call-generic-in-impl.rs | 2 +- .../traits/const-traits/call-generic-method-chain.rs | 2 +- .../const-traits/call-generic-method-dup-bound.rs | 2 +- .../traits/const-traits/call-generic-method-fail.rs | 2 +- .../traits/const-traits/call-generic-method-pass.rs | 2 +- .../const_derives/derive-const-with-params.rs | 2 +- 17 files changed, 29 insertions(+), 28 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index b1ca3701fa5ae..03b120fbf0c34 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -248,7 +248,7 @@ use crate::ops::ControlFlow; )] #[rustc_diagnostic_item = "PartialEq"] #[const_trait] -#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub trait PartialEq: PointeeSized { /// Tests for `self` and `other` values to be equal, and is used by `==`. #[must_use] @@ -1809,7 +1809,7 @@ mod impls { macro_rules! partial_eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq for $t { #[inline] fn eq(&self, other: &Self) -> bool { *self == *other } @@ -2017,7 +2017,7 @@ mod impls { // & pointers #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq<&B> for &A where A: ~const PartialEq, @@ -2089,7 +2089,7 @@ mod impls { // &mut pointers #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq<&mut B> for &mut A where A: ~const PartialEq, @@ -2159,7 +2159,7 @@ mod impls { impl Eq for &mut A where A: Eq {} #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq<&mut B> for &A where A: ~const PartialEq, @@ -2175,7 +2175,7 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] impl const PartialEq<&B> for &mut A where A: ~const PartialEq, diff --git a/tests/ui/const-generics/issues/issue-90318.rs b/tests/ui/const-generics/issues/issue-90318.rs index dfba90a557512..239171217ebab 100644 --- a/tests/ui/const-generics/issues/issue-90318.rs +++ b/tests/ui/const-generics/issues/issue-90318.rs @@ -1,6 +1,6 @@ #![feature(const_type_id)] #![feature(generic_const_exprs)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_cmp)] #![feature(core_intrinsics)] #![allow(incomplete_features)] diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index def615bd92bb5..db2d50f4d22c9 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -#![feature(const_type_id, const_trait_impl)] +#![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id.rs b/tests/ui/consts/const_transmute_type_id.rs index 56ead6a622b2c..a2d4cf378309d 100644 --- a/tests/ui/consts/const_transmute_type_id.rs +++ b/tests/ui/consts/const_transmute_type_id.rs @@ -1,4 +1,4 @@ -#![feature(const_type_id, const_trait_impl)] +#![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id2.rs b/tests/ui/consts/const_transmute_type_id2.rs index e29cf8171acbe..3ceb2b942b04a 100644 --- a/tests/ui/consts/const_transmute_type_id2.rs +++ b/tests/ui/consts/const_transmute_type_id2.rs @@ -1,6 +1,6 @@ //@ normalize-stderr: "0x(ff)+" -> "" -#![feature(const_type_id, const_trait_impl)] +#![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs index a870d6e7e801c..ed5ff769701f2 100644 --- a/tests/ui/consts/const_transmute_type_id3.rs +++ b/tests/ui/consts/const_transmute_type_id3.rs @@ -1,4 +1,4 @@ -#![feature(const_type_id, const_trait_impl)] +#![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/const_transmute_type_id4.rs b/tests/ui/consts/const_transmute_type_id4.rs index bc71f961a51b6..22a607e9e0e22 100644 --- a/tests/ui/consts/const_transmute_type_id4.rs +++ b/tests/ui/consts/const_transmute_type_id4.rs @@ -1,4 +1,4 @@ -#![feature(const_type_id, const_trait_impl)] +#![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; diff --git a/tests/ui/consts/issue-73976-monomorphic.rs b/tests/ui/consts/issue-73976-monomorphic.rs index 3bfdb397afb23..5f364cd995e02 100644 --- a/tests/ui/consts/issue-73976-monomorphic.rs +++ b/tests/ui/consts/issue-73976-monomorphic.rs @@ -8,6 +8,7 @@ #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_trait_impl)] +#![feature(const_cmp)] use std::any::{self, TypeId}; diff --git a/tests/ui/consts/issue-90870.rs b/tests/ui/consts/issue-90870.rs index f807ae75ee5e1..053763b9f894b 100644 --- a/tests/ui/consts/issue-90870.rs +++ b/tests/ui/consts/issue-90870.rs @@ -3,9 +3,9 @@ #![allow(dead_code)] const fn f(a: &u8, b: &u8) -> bool { - //~^ HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable - //~| HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable - //~| HELP: add `#![feature(const_trait_impl)]` to the crate attributes to enable + //~^ HELP: add `#![feature(const_cmp)]` to the crate attributes to enable + //~| HELP: add `#![feature(const_cmp)]` to the crate attributes to enable + //~| HELP: add `#![feature(const_cmp)]` to the crate attributes to enable a == b //~^ ERROR: cannot call conditionally-const operator in constant functions //~| ERROR: `PartialEq` is not yet stable as a const trait diff --git a/tests/ui/consts/issue-90870.stderr b/tests/ui/consts/issue-90870.stderr index 8d6f21fd82fbe..60993f2586427 100644 --- a/tests/ui/consts/issue-90870.stderr +++ b/tests/ui/consts/issue-90870.stderr @@ -19,9 +19,9 @@ error: `PartialEq` is not yet stable as a const trait LL | a == b | ^^^^^^ | -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +help: add `#![feature(const_cmp)]` to the crate attributes to enable | -LL + #![feature(const_trait_impl)] +LL + #![feature(const_cmp)] | error[E0658]: cannot call conditionally-const operator in constant functions @@ -45,9 +45,9 @@ error: `PartialEq` is not yet stable as a const trait LL | a == b | ^^^^^^ | -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +help: add `#![feature(const_cmp)]` to the crate attributes to enable | -LL + #![feature(const_trait_impl)] +LL + #![feature(const_cmp)] | error[E0658]: cannot call conditionally-const operator in constant functions @@ -71,9 +71,9 @@ error: `PartialEq` is not yet stable as a const trait LL | if l == r { | ^^^^^^ | -help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +help: add `#![feature(const_cmp)]` to the crate attributes to enable | -LL + #![feature(const_trait_impl)] +LL + #![feature(const_cmp)] | error: aborting due to 6 previous errors diff --git a/tests/ui/traits/const-traits/call-const-trait-method-pass.rs b/tests/ui/traits/const-traits/call-const-trait-method-pass.rs index d66a11490c59d..2d9c2ca086178 100644 --- a/tests/ui/traits/const-traits/call-const-trait-method-pass.rs +++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.rs @@ -1,4 +1,4 @@ -#![feature(const_trait_impl, const_ops)] +#![feature(const_trait_impl, const_ops, const_cmp)] //@ check-pass struct Int(i32); diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.rs b/tests/ui/traits/const-traits/call-generic-in-impl.rs index f38590fa3c012..72fc80c50e02a 100644 --- a/tests/ui/traits/const-traits/call-generic-in-impl.rs +++ b/tests/ui/traits/const-traits/call-generic-in-impl.rs @@ -1,5 +1,5 @@ //@ check-pass -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_cmp)] #[const_trait] trait MyPartialEq { diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.rs b/tests/ui/traits/const-traits/call-generic-method-chain.rs index 1ad71c424a3bd..db053b4807919 100644 --- a/tests/ui/traits/const-traits/call-generic-method-chain.rs +++ b/tests/ui/traits/const-traits/call-generic-method-chain.rs @@ -3,7 +3,7 @@ //@ compile-flags: -Znext-solver //@ check-pass -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_cmp)] struct S; diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs index 58f293b5ac5cd..5913cbf8a21d0 100644 --- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs +++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Znext-solver //@ check-pass -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_cmp)] struct S; diff --git a/tests/ui/traits/const-traits/call-generic-method-fail.rs b/tests/ui/traits/const-traits/call-generic-method-fail.rs index 4528f3b122f97..6744176d40a1b 100644 --- a/tests/ui/traits/const-traits/call-generic-method-fail.rs +++ b/tests/ui/traits/const-traits/call-generic-method-fail.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_cmp)] pub const fn equals_self(t: &T) -> bool { *t == *t diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.rs b/tests/ui/traits/const-traits/call-generic-method-pass.rs index aa52a7b9e473e..01c5860c8ec5e 100644 --- a/tests/ui/traits/const-traits/call-generic-method-pass.rs +++ b/tests/ui/traits/const-traits/call-generic-method-pass.rs @@ -3,7 +3,7 @@ //@ compile-flags: -Znext-solver //@ check-pass -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_cmp)] struct S; diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs index b39f97b59382b..bbc0faee10f83 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.rs @@ -1,7 +1,7 @@ //@ check-pass #![feature(derive_const)] -#![feature(const_trait_impl)] +#![feature(const_trait_impl, const_cmp)] #[derive_const(PartialEq)] pub struct Reverse(T); From b94083e87fcbacaf9d76176742d2fe984b5aaae4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Jul 2025 17:57:46 +0200 Subject: [PATCH 12/25] fix const_ops tracking issue --- library/core/src/ops/arith.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index e53c128efe069..7d44b1733b9c6 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -65,7 +65,7 @@ /// ``` #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "90080")] +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] #[rustc_on_unimplemented( on(all(Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",), on(all(Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",), @@ -96,7 +96,7 @@ pub trait Add { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const Add for $t { type Output = $t; @@ -179,7 +179,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 /// ``` #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "90080")] +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] #[rustc_on_unimplemented( message = "cannot subtract `{Rhs}` from `{Self}`", label = "no implementation for `{Self} - {Rhs}`", @@ -208,7 +208,7 @@ pub trait Sub { macro_rules! sub_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const Sub for $t { type Output = $t; @@ -313,7 +313,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "90080")] +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] #[diagnostic::on_unimplemented( message = "cannot multiply `{Self}` by `{Rhs}`", label = "no implementation for `{Self} * {Rhs}`" @@ -341,7 +341,7 @@ pub trait Mul { macro_rules! mul_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const Mul for $t { type Output = $t; @@ -450,7 +450,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 /// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "90080")] +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] #[diagnostic::on_unimplemented( message = "cannot divide `{Self}` by `{Rhs}`", label = "no implementation for `{Self} / {Rhs}`" @@ -484,7 +484,7 @@ macro_rules! div_impl_integer { /// #[doc = $panic] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const Div for $t { type Output = $t; @@ -505,7 +505,7 @@ div_impl_integer! { macro_rules! div_impl_float { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const Div for $t { type Output = $t; @@ -556,7 +556,7 @@ div_impl_float! { f16 f32 f64 f128 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "90080")] +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] #[diagnostic::on_unimplemented( message = "cannot calculate the remainder of `{Self}` divided by `{Rhs}`", label = "no implementation for `{Self} % {Rhs}`" @@ -590,7 +590,7 @@ macro_rules! rem_impl_integer { /// #[doc = $panic] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const Rem for $t { type Output = $t; @@ -626,7 +626,7 @@ macro_rules! rem_impl_float { /// assert_eq!(x % y, remainder); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_ops", issue = "90080")] + #[rustc_const_unstable(feature = "const_ops", issue = "143802")] impl const Rem for $t { type Output = $t; From d004abb4d3d7a4c50c54ffb3c4f227ff0d689f03 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Fri, 11 Jul 2025 20:36:13 +0530 Subject: [PATCH 13/25] remove format short command and push format short command method inside fingerprint impl --- src/bootstrap/src/utils/exec.rs | 29 ++++------------------------- src/bootstrap/src/utils/tracing.rs | 2 -- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index c5bafda88c459..ebc18f11a05ae 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -76,8 +76,10 @@ pub struct CommandFingerprint { cwd: Option, } -impl FormatShortCmd for CommandFingerprint { - fn format_short_cmd(&self) -> String { +impl CommandFingerprint { + /// Helper method to format both Command and BootstrapCommand as a short execution line, + /// without all the other details (e.g. environment variables). + pub fn format_short_cmd(&self) -> String { let program = Path::new(&self.program); let mut line = vec![program.file_name().unwrap().to_str().unwrap().to_owned()]; line.extend(self.args.iter().map(|arg| arg.to_string_lossy().into_owned())); @@ -545,29 +547,6 @@ impl Default for CommandOutput { } } -/// Helper trait to format both Command and BootstrapCommand as a short execution line, -/// without all the other details (e.g. environment variables). -pub trait FormatShortCmd { - fn format_short_cmd(&self) -> String; -} - -#[cfg(feature = "tracing")] -impl FormatShortCmd for BootstrapCommand { - fn format_short_cmd(&self) -> String { - self.command.format_short_cmd() - } -} - -#[cfg(feature = "tracing")] -impl FormatShortCmd for Command { - fn format_short_cmd(&self) -> String { - let program = Path::new(self.get_program()); - let mut line = vec![program.file_name().unwrap().to_str().unwrap()]; - line.extend(self.get_args().map(|arg| arg.to_str().unwrap())); - line.join(" ") - } -} - #[derive(Clone, Default)] pub struct ExecutionContext { dry_run: DryRun, diff --git a/src/bootstrap/src/utils/tracing.rs b/src/bootstrap/src/utils/tracing.rs index 58d127dfb791d..109407bc5f235 100644 --- a/src/bootstrap/src/utils/tracing.rs +++ b/src/bootstrap/src/utils/tracing.rs @@ -52,8 +52,6 @@ macro_rules! error { macro_rules! trace_cmd { ($cmd:expr) => { { - use $crate::utils::exec::FormatShortCmd; - ::tracing::span!( target: "COMMAND", ::tracing::Level::TRACE, From 5e203851f7203d5ad4298d54c50008f24a34b793 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 9 Jul 2025 14:25:23 -0700 Subject: [PATCH 14/25] random: Provide a `Distribution` trait This will let people make calls like random(1..=6), and allows for future expansion to non-uniform distributions, as well as floating-point. For now, this is only implemented for `RangeFull`, to get the interface in place. Subsequent commits will implement it for other range types. --- library/core/src/primitive_docs.rs | 2 -- library/core/src/random.rs | 47 +++++++++++++----------------- library/core/src/tuple.rs | 11 ------- library/std/src/random.rs | 24 +++++---------- 4 files changed, 27 insertions(+), 57 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 2c77c55745b46..5bd80149a1d6e 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1081,13 +1081,11 @@ mod prim_str {} /// * [`Debug`] /// * [`Default`] /// * [`Hash`] -/// * [`Random`] /// * [`From<[T; N]>`][from] /// /// [from]: convert::From /// [`Debug`]: fmt::Debug /// [`Hash`]: hash::Hash -/// [`Random`]: random::Random /// /// The following traits are implemented for tuples of any length. These traits have /// implementations that are automatically generated by the compiler, so are not limited by diff --git a/library/core/src/random.rs b/library/core/src/random.rs index 40338c3f4ac70..8a51fb289d8f3 100644 --- a/library/core/src/random.rs +++ b/library/core/src/random.rs @@ -1,7 +1,6 @@ //! Random value generation. -//! -//! The [`Random`] trait allows generating a random value for a type using a -//! given [`RandomSource`]. + +use crate::range::RangeFull; /// A source of randomness. #[unstable(feature = "random", issue = "130703")] @@ -15,39 +14,33 @@ pub trait RandomSource { fn fill_bytes(&mut self, bytes: &mut [u8]); } -/// A trait for getting a random value for a type. -/// -/// **Warning:** Be careful when manipulating random values! The -/// [`random`](Random::random) method on integers samples them with a uniform -/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using -/// modulo operations, some of the resulting values can become more likely than -/// others. Use audited crates when in doubt. +/// A trait representing a distribution of random values for a type. #[unstable(feature = "random", issue = "130703")] -pub trait Random: Sized { - /// Generates a random value. - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self; +pub trait Distribution { + /// Samples a random value from the distribution, using the specified random source. + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> T; +} + +impl> Distribution for &DT { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> T { + (*self).sample(source) + } } -impl Random for bool { - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { - u8::random(source) & 1 == 1 +impl Distribution for RangeFull { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> bool { + let byte: u8 = RangeFull.sample(source); + byte & 1 == 1 } } macro_rules! impl_primitive { ($t:ty) => { - impl Random for $t { - /// Generates a random value. - /// - /// **Warning:** Be careful when manipulating the resulting value! This - /// method samples according to a uniform distribution, so a value of 1 is - /// just as likely as [`MAX`](Self::MAX). By using modulo operations, some - /// values can become more likely than others. Use audited crates when in - /// doubt. - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { - let mut bytes = (0 as Self).to_ne_bytes(); + impl Distribution<$t> for RangeFull { + fn sample(&self, source: &mut (impl RandomSource + ?Sized)) -> $t { + let mut bytes = (0 as $t).to_ne_bytes(); source.fill_bytes(&mut bytes); - Self::from_ne_bytes(bytes) + <$t>::from_ne_bytes(bytes) } } }; diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 9cf08e74ff692..23a0a6877df77 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -3,7 +3,6 @@ use crate::cmp::Ordering::{self, *}; use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; use crate::ops::ControlFlow::{self, Break, Continue}; -use crate::random::{Random, RandomSource}; // Recursive macro for implementing n-ary tuple functions and operations // @@ -131,16 +130,6 @@ macro_rules! tuple_impls { } } - maybe_tuple_doc! { - $($T)+ @ - #[unstable(feature = "random", issue = "130703")] - impl<$($T: Random),+> Random for ($($T,)+) { - fn random(source: &mut (impl RandomSource + ?Sized)) -> Self { - ($({ let x: $T = Random::random(source); x},)+) - } - } - } - maybe_tuple_doc! { $($T)+ @ #[stable(feature = "array_tuple_conv", since = "1.71.0")] diff --git a/library/std/src/random.rs b/library/std/src/random.rs index e7d4ab81df0ac..3994c5cfaf6f4 100644 --- a/library/std/src/random.rs +++ b/library/std/src/random.rs @@ -1,7 +1,4 @@ //! Random value generation. -//! -//! The [`Random`] trait allows generating a random value for a type using a -//! given [`RandomSource`]. #[unstable(feature = "random", issue = "130703")] pub use core::random::*; @@ -68,18 +65,11 @@ impl RandomSource for DefaultRandomSource { } } -/// Generates a random value with the default random source. +/// Generates a random value from a distribution, using the default random source. /// -/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and -/// will sample according to the same distribution as the underlying [`Random`] -/// trait implementation. See [`DefaultRandomSource`] for more information about -/// how randomness is sourced. -/// -/// **Warning:** Be careful when manipulating random values! The -/// [`random`](Random::random) method on integers samples them with a uniform -/// distribution, so a value of 1 is just as likely as [`i32::MAX`]. By using -/// modulo operations, some of the resulting values can become more likely than -/// others. Use audited crates when in doubt. +/// This is a convenience function for `dist.sample(&mut DefaultRandomSource)` and will sample +/// according to the same distribution as the underlying [`Distribution`] trait implementation. See +/// [`DefaultRandomSource`] for more information about how randomness is sourced. /// /// # Examples /// @@ -89,7 +79,7 @@ impl RandomSource for DefaultRandomSource { /// /// use std::random::random; /// -/// let bits: u128 = random(); +/// let bits: u128 = random(..); /// let g1 = (bits >> 96) as u32; /// let g2 = (bits >> 80) as u16; /// let g3 = (0x4000 | (bits >> 64) & 0x0fff) as u16; @@ -101,6 +91,6 @@ impl RandomSource for DefaultRandomSource { /// /// [version 4/variant 1 UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) #[unstable(feature = "random", issue = "130703")] -pub fn random() -> T { - T::random(&mut DefaultRandomSource) +pub fn random(dist: impl Distribution) -> T { + dist.sample(&mut DefaultRandomSource) } From 900aa00584d58bf771b4d1b227be2ff453426234 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 11 Jul 2025 11:13:47 -0700 Subject: [PATCH 15/25] Update miri for change to random API --- src/tools/miri/tests/pass/shims/random.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/pass/shims/random.rs b/src/tools/miri/tests/pass/shims/random.rs index ae75ebdcd3f32..2a5c8993662be 100644 --- a/src/tools/miri/tests/pass/shims/random.rs +++ b/src/tools/miri/tests/pass/shims/random.rs @@ -1,5 +1,5 @@ #![feature(random)] fn main() { - let _x: i32 = std::random::random(); + let _x: i32 = std::random::random(..); } From 3751e133bca55dbec521ccb36132fa0bdbf10b88 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Sat, 5 Jul 2025 22:26:40 -0400 Subject: [PATCH 16/25] slice: Mark `rotate_left`, `rotate_right` unstably const --- library/core/src/slice/mod.rs | 6 ++++-- library/core/src/slice/rotate.rs | 24 +++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dc09ba8d788fc..7df717751f522 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3668,7 +3668,8 @@ impl [T] { /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] - pub fn rotate_left(&mut self, mid: usize) { + #[rustc_const_unstable(feature = "const_slice_rotate", issue = "143812")] + pub const fn rotate_left(&mut self, mid: usize) { assert!(mid <= self.len()); let k = self.len() - mid; let p = self.as_mut_ptr(); @@ -3713,7 +3714,8 @@ impl [T] { /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] - pub fn rotate_right(&mut self, k: usize) { + #[rustc_const_unstable(feature = "const_slice_rotate", issue = "143812")] + pub const fn rotate_right(&mut self, k: usize) { assert!(k <= self.len()); let mid = self.len() - k; let p = self.as_mut_ptr(); diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs index 80178f297eaae..b3b64422884d5 100644 --- a/library/core/src/slice/rotate.rs +++ b/library/core/src/slice/rotate.rs @@ -1,5 +1,5 @@ use crate::mem::{MaybeUninit, SizedTypeProperties}; -use crate::{cmp, ptr}; +use crate::ptr; type BufType = [usize; 32]; @@ -11,7 +11,7 @@ type BufType = [usize; 32]; /// /// The specified range must be valid for reading and writing. #[inline] -pub(super) unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { +pub(super) const unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { if T::IS_ZST { return; } @@ -21,7 +21,8 @@ pub(super) unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { } // `T` is not a zero-sized type, so it's okay to divide by its size. if !cfg!(feature = "optimize_for_size") - && cmp::min(left, right) <= size_of::() / size_of::() + // FIXME(const-hack): Use cmp::min when available in const + && const_min(left, right) <= size_of::() / size_of::() { // SAFETY: guaranteed by the caller unsafe { ptr_rotate_memmove(left, mid, right) }; @@ -45,7 +46,7 @@ pub(super) unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { /// /// The specified range must be valid for reading and writing. #[inline] -unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { +const unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { // The `[T; 0]` here is to ensure this is appropriately aligned for T let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); let buf = rawarray.as_mut_ptr() as *mut T; @@ -117,7 +118,7 @@ unsafe fn ptr_rotate_memmove(left: usize, mid: *mut T, right: usize) { /// /// The specified range must be valid for reading and writing. #[inline] -unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { +const unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { // Algorithm 2 // Microbenchmarks indicate that the average performance for random shifts is better all // the way until about `left + right == 32`, but the worst case performance breaks even @@ -175,7 +176,9 @@ unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { } } // finish the chunk with more rounds - for start in 1..gcd { + // FIXME(const-hack): Use `for start in 1..gcd` when available in const + let mut start = 1; + while start < gcd { // SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for // reading and writing as per the function's safety contract, see [long-safety-expl] // above @@ -201,6 +204,8 @@ unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { i += right; } } + + start += 1; } } @@ -222,7 +227,7 @@ unsafe fn ptr_rotate_gcd(left: usize, mid: *mut T, right: usize) { /// /// The specified range must be valid for reading and writing. #[inline] -unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) { +const unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) { loop { if left >= right { // Algorithm 3 @@ -265,3 +270,8 @@ unsafe fn ptr_rotate_swap(mut left: usize, mut mid: *mut T, mut right: usize) } } } + +// FIXME(const-hack): Use cmp::min when available in const +const fn const_min(left: usize, right: usize) -> usize { + if right < left { right } else { left } +} From 507fd38a3fd2121d4a39df6fcf14eb50f868d471 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 11 Jul 2025 13:56:18 -0500 Subject: [PATCH 17/25] htmldocck: better error messages for negative raw directives --- src/etc/htmldocck.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 1806e2be9bb27..ddbd256a0d8c9 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -564,10 +564,14 @@ def check_command(c, cache): # hasraw/matchesraw = string test elif len(c.args) == 2 and "raw" in c.cmd: cerr = "`PATTERN` did not match" + if c.negated: + cerr = "`PATTERN` unexpectedly matched" ret = check_string(cache.get_file(c.args[0]), c.args[1], regexp) # has/matches = XML tree test elif len(c.args) == 3 and "raw" not in c.cmd: cerr = "`XPATH PATTERN` did not match" + if c.negated: + cerr = "`XPATH PATTERN` unexpectedly matched" ret = get_nb_matching_elements(cache, c, regexp, True) != 0 else: raise InvalidCheck("Invalid number of {} arguments".format(c.cmd)) From 0528cc9638a93ec72e6b1161536b42b5aeb874cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 11 Jul 2025 22:43:02 +0200 Subject: [PATCH 18/25] Access `wasi_sdk_path` instead of reading environment variable in bootstrap --- src/bootstrap/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d9a4da8f3cc01..9906dca42885f 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1318,7 +1318,7 @@ impl Build { if let Some(path) = configured { return Some(path.join("lib").join(target.to_string())); } - let mut env_root = PathBuf::from(std::env::var_os("WASI_SDK_PATH")?); + let mut env_root = self.wasi_sdk_path.clone()?; env_root.push("share"); env_root.push("wasi-sysroot"); env_root.push("lib"); From b0e4c3594f4d52ffde5281bae752e5ff05bd029c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Jul 2025 09:39:29 +0200 Subject: [PATCH 19/25] ./x test miri: fix cleaning the miri_ui directory --- src/bootstrap/src/core/build_steps/test.rs | 9 +++++++-- src/tools/miri/tests/ui.rs | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 716bef3f38c49..5dbfd522844ed 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -556,8 +556,13 @@ impl Step for Miri { // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when // the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors. if !builder.config.dry_run() { - let ui_test_dep_dir = - builder.stage_out(miri.build_compiler, Mode::ToolStd).join("miri_ui"); + // This has to match `CARGO_TARGET_TMPDIR` in Miri's `ui.rs`. + // This means we need `host` here as that's the target `ui.rs` is built for. + let ui_test_dep_dir = builder + .stage_out(miri.build_compiler, Mode::ToolStd) + .join(host) + .join("tmp") + .join("miri_ui"); // The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see // ). // We can hence use that directly as a signal to clear the ui test dir. diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index 5239f8338ee1a..43f855d57dd57 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -97,6 +97,8 @@ fn miri_config( let mut config = Config { target: Some(target.to_owned()), program, + // When changing this, remember to also adjust the logic in bootstrap, in Miri's test step, + // that deletes the `miri_ui` dir when it needs a rebuild. out_dir: PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join("miri_ui"), threads: std::env::var("MIRI_TEST_THREADS") .ok() From 33668c1b0e02c6c6f8d195bc6545ceef5297cc87 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 5 Jul 2025 15:35:26 +0800 Subject: [PATCH 20/25] Remove outdated debugger version warning --- src/tools/compiletest/src/debuggers.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index 0edc3d82d4f56..8afe3289fa45a 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -51,17 +51,6 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> { pub(crate) fn configure_lldb(config: &Config) -> Option> { config.lldb_python_dir.as_ref()?; - // FIXME: this is super old - if let Some(350) = config.lldb_version { - println!( - "WARNING: The used version of LLDB (350) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - ); - return None; - } - Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) } From 832b6273bdc5bbbe22d7274a5c424d818fad0ef8 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 15:57:40 +0800 Subject: [PATCH 21/25] Move `string_enum` to `util` module --- src/tools/compiletest/src/common.rs | 46 ++--------------------------- src/tools/compiletest/src/tests.rs | 6 +--- src/tools/compiletest/src/util.rs | 39 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 49 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 7122746fa87eb..bbc002a9b876b 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -1,8 +1,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; +use std::iter; use std::process::Command; -use std::str::FromStr; use std::sync::OnceLock; -use std::{fmt, iter}; use build_helper::git::GitConfig; use camino::{Utf8Path, Utf8PathBuf}; @@ -12,48 +11,7 @@ use serde::de::{Deserialize, Deserializer, Error as _}; pub use self::Mode::*; use crate::executor::{ColorConfig, OutputFormat}; use crate::fatal; -use crate::util::{Utf8PathBufExt, add_dylib_path}; - -macro_rules! string_enum { - ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => { - $(#[$meta])* - $vis enum $name { - $($variant,)* - } - - impl $name { - $vis const VARIANTS: &'static [Self] = &[$(Self::$variant,)*]; - $vis const STR_VARIANTS: &'static [&'static str] = &[$(Self::$variant.to_str(),)*]; - - $vis const fn to_str(&self) -> &'static str { - match self { - $(Self::$variant => $repr,)* - } - } - } - - impl fmt::Display for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.to_str(), f) - } - } - - impl FromStr for $name { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - $($repr => Ok(Self::$variant),)* - _ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)), - } - } - } - } -} - -// Make the macro visible outside of this module, for tests. -#[cfg(test)] -pub(crate) use string_enum; +use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; string_enum! { #[derive(Clone, Copy, PartialEq, Debug)] diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index e3e4a81755d09..174ec9381f6c9 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -67,11 +67,7 @@ fn is_test_test() { #[test] fn string_enums() { - // These imports are needed for the macro-generated code - use std::fmt; - use std::str::FromStr; - - crate::common::string_enum! { + crate::util::string_enum! { #[derive(Clone, Copy, Debug, PartialEq)] enum Animal { Cat => "meow", diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 202582bea8c13..fb047548c456a 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -104,3 +104,42 @@ macro_rules! static_regex { }}; } pub(crate) use static_regex; + +macro_rules! string_enum { + ($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => { + $(#[$meta])* + $vis enum $name { + $($variant,)* + } + + impl $name { + $vis const VARIANTS: &'static [Self] = &[$(Self::$variant,)*]; + $vis const STR_VARIANTS: &'static [&'static str] = &[$(Self::$variant.to_str(),)*]; + + $vis const fn to_str(&self) -> &'static str { + match self { + $(Self::$variant => $repr,)* + } + } + } + + impl ::std::fmt::Display for $name { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::std::fmt::Display::fmt(self.to_str(), f) + } + } + + impl ::std::str::FromStr for $name { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + $($repr => Ok(Self::$variant),)* + _ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)), + } + } + } + } +} + +pub(crate) use string_enum; From b4dfd51bac242deca51442355784274beb16bd43 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 15:59:16 +0800 Subject: [PATCH 22/25] Do not allow defaults for `Mode` and `Config` They do not have sensible defaults, and it is crucial that we get them right. --- src/tools/compiletest/src/common.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index bbc002a9b876b..943e800e72cfb 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -34,12 +34,6 @@ string_enum! { } } -impl Default for Mode { - fn default() -> Self { - Mode::Ui - } -} - impl Mode { pub fn aux_dir_disambiguator(self) -> &'static str { // Pretty-printing tests could run concurrently, and if they do, @@ -151,7 +145,7 @@ pub enum Sanitizer { /// /// FIXME: audit these options to make sure we are not hashing less than necessary for build stamp /// (for changed test detection). -#[derive(Debug, Default, Clone)] +#[derive(Debug, Clone)] pub struct Config { /// Some test [`Mode`]s support [snapshot testing], where a *reference snapshot* of outputs (of /// `stdout`, `stderr`, or other form of artifacts) can be compared to the *actual output*. From 4aad9ab8aa7c6ee692453a9544c696f03e281dbd Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 16:02:05 +0800 Subject: [PATCH 23/25] Rename `Mode` to `TestMode` It is *critical* that we maintain clear nomenclature in `compiletest`. We have many types of "modes" in `compiletest` -- pass modes, coverage modes, compare modes, you name it. `Mode` is also a *super* general term. Rename it to `TestMode` to leave no room for such ambiguity. As a follow-up, I also intend to introduce an enum for `TestSuite`, then rid of all usage of glob re-exported `TestMode::*` enum variants -- many test suites share the same name as the test mode. --- src/tools/compiletest/src/common.rs | 24 ++++++------ src/tools/compiletest/src/directives.rs | 38 +++++++++---------- src/tools/compiletest/src/directives/tests.rs | 4 +- src/tools/compiletest/src/lib.rs | 20 +++++----- src/tools/compiletest/src/runtest.rs | 2 +- src/tools/rustdoc-gui-test/src/main.rs | 2 +- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 943e800e72cfb..d621ee8de4fbd 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -8,14 +8,14 @@ use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; -pub use self::Mode::*; +pub use self::TestMode::*; use crate::executor::{ColorConfig, OutputFormat}; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; string_enum! { #[derive(Clone, Copy, PartialEq, Debug)] - pub enum Mode { + pub enum TestMode { Pretty => "pretty", DebugInfo => "debuginfo", Codegen => "codegen", @@ -34,7 +34,7 @@ string_enum! { } } -impl Mode { +impl TestMode { pub fn aux_dir_disambiguator(self) -> &'static str { // Pretty-printing tests could run concurrently, and if they do, // they need to keep their output segregated. @@ -147,7 +147,7 @@ pub enum Sanitizer { /// (for changed test detection). #[derive(Debug, Clone)] pub struct Config { - /// Some test [`Mode`]s support [snapshot testing], where a *reference snapshot* of outputs (of + /// Some [`TestMode`]s support [snapshot testing], where a *reference snapshot* of outputs (of /// `stdout`, `stderr`, or other form of artifacts) can be compared to the *actual output*. /// /// This option can be set to `true` to update the *reference snapshots* in-place, otherwise @@ -269,20 +269,20 @@ pub struct Config { /// FIXME: reconsider this string; this is hashed for test build stamp. pub stage_id: String, - /// The test [`Mode`]. E.g. [`Mode::Ui`]. Each test mode can correspond to one or more test + /// The [`TestMode`]. E.g. [`TestMode::Ui`]. Each test mode can correspond to one or more test /// suites. /// /// FIXME: stop using stringly-typed test suites! - pub mode: Mode, + pub mode: TestMode, /// The test suite. /// - /// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the [`Mode::Ui`] - /// test *mode*. + /// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the + /// [`TestMode::Ui`] test *mode*. /// /// Note that the same test directory (e.g. `tests/coverage/`) may correspond to multiple test - /// modes, e.g. `tests/coverage/` can be run under both [`Mode::CoverageRun`] and - /// [`Mode::CoverageMap`]. + /// modes, e.g. `tests/coverage/` can be run under both [`TestMode::CoverageRun`] and + /// [`TestMode::CoverageMap`]. /// /// FIXME: stop using stringly-typed test suites! pub suite: String, @@ -538,8 +538,8 @@ pub struct Config { // Configuration for various run-make tests frobbing things like C compilers or querying about // various LLVM component information. // - // FIXME: this really should be better packaged together. - // FIXME: these need better docs, e.g. for *host*, or for *target*? + // FIXME: this really should be better packaged together. FIXME: these need better docs, e.g. + // for *host*, or for *target*? pub cc: String, pub cxx: String, pub cflags: String, diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index a6242cf0c225a..ddd04376082c7 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use tracing::*; -use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; +use crate::common::{Config, Debugger, FailMode, PassMode, TestMode}; use crate::debuggers::{extract_cdb_version, extract_gdb_version}; use crate::directives::auxiliary::{AuxProps, parse_and_update_aux}; use crate::directives::needs::CachedNeedsConditions; @@ -328,7 +328,7 @@ impl TestProps { props.exec_env.push(("RUSTC".to_string(), config.rustc_path.to_string())); match (props.pass_mode, props.fail_mode) { - (None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check), + (None, None) if config.mode == TestMode::Ui => props.fail_mode = Some(FailMode::Check), (Some(_), Some(_)) => panic!("cannot use a *-fail and *-pass mode together"), _ => {} } @@ -609,11 +609,11 @@ impl TestProps { self.failure_status = Some(101); } - if config.mode == Mode::Incremental { + if config.mode == TestMode::Incremental { self.incremental = true; } - if config.mode == Mode::Crashes { + if config.mode == TestMode::Crashes { // we don't want to pollute anything with backtrace-files // also turn off backtraces in order to save some execution // time on the tests; we only need to know IF it crashes @@ -641,11 +641,11 @@ impl TestProps { fn update_fail_mode(&mut self, ln: &str, config: &Config) { let check_ui = |mode: &str| { // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows - if config.mode != Mode::Ui && config.mode != Mode::Crashes { + if config.mode != TestMode::Ui && config.mode != TestMode::Crashes { panic!("`{}-fail` directive is only supported in UI tests", mode); } }; - if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") { + if config.mode == TestMode::Ui && config.parse_name_directive(ln, "compile-fail") { panic!("`compile-fail` directive is useless in UI tests"); } let fail_mode = if config.parse_name_directive(ln, "check-fail") { @@ -669,10 +669,10 @@ impl TestProps { fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) { let check_no_run = |s| match (config.mode, s) { - (Mode::Ui, _) => (), - (Mode::Crashes, _) => (), - (Mode::Codegen, "build-pass") => (), - (Mode::Incremental, _) => { + (TestMode::Ui, _) => (), + (TestMode::Crashes, _) => (), + (TestMode::Codegen, "build-pass") => (), + (TestMode::Incremental, _) => { if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) { panic!("`{s}` directive is only supported in `cfail` incremental tests") } @@ -715,7 +715,7 @@ impl TestProps { pub fn update_add_core_stubs(&mut self, ln: &str, config: &Config) { let add_core_stubs = config.parse_name_directive(ln, directives::ADD_CORE_STUBS); if add_core_stubs { - if !matches!(config.mode, Mode::Ui | Mode::Codegen | Mode::Assembly) { + if !matches!(config.mode, TestMode::Ui | TestMode::Codegen | TestMode::Assembly) { panic!( "`add-core-stubs` is currently only supported for ui, codegen and assembly test modes" ); @@ -833,7 +833,7 @@ pub(crate) struct CheckDirectiveResult<'ln> { pub(crate) fn check_directive<'a>( directive_ln: &'a str, - mode: Mode, + mode: TestMode, original_line: &str, ) -> CheckDirectiveResult<'a> { let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, "")); @@ -842,11 +842,11 @@ pub(crate) fn check_directive<'a>( let is_known = |s: &str| { KNOWN_DIRECTIVE_NAMES.contains(&s) || match mode { - Mode::Rustdoc | Mode::RustdocJson => { + TestMode::Rustdoc | TestMode::RustdocJson => { original_line.starts_with("//@") && match mode { - Mode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, - Mode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES, + TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, + TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES, _ => unreachable!(), } .contains(&s) @@ -868,7 +868,7 @@ pub(crate) fn check_directive<'a>( const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; fn iter_directives( - mode: Mode, + mode: TestMode, _suite: &str, poisoned: &mut bool, testfile: &Utf8Path, @@ -883,7 +883,7 @@ fn iter_directives( // specify them manually in every test file. // // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. - if mode == Mode::CoverageRun { + if mode == TestMode::CoverageRun { let extra_directives: &[&str] = &[ "needs-profiler-runtime", // FIXME(pietroalbini): this test currently does not work on cross-compiled targets @@ -964,7 +964,7 @@ impl Config { ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"]; if let Some(raw) = self.parse_name_value_directive(line, "revisions") { - if self.mode == Mode::RunMake { + if self.mode == TestMode::RunMake { panic!("`run-make` tests do not support revisions: {}", testfile); } @@ -981,7 +981,7 @@ impl Config { ); } - if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt) + if matches!(self.mode, TestMode::Assembly | TestMode::Codegen | TestMode::MirOpt) && FILECHECK_FORBIDDEN_REVISION_NAMES.contains(&revision) { panic!( diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index d4570f8267781..9c5751b416b25 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -7,7 +7,7 @@ use super::{ DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives, parse_normalize_rule, }; -use crate::common::{Config, Debugger, Mode}; +use crate::common::{Config, Debugger, TestMode}; use crate::executor::{CollectedTestDesc, ShouldPanic}; fn make_test_description( @@ -785,7 +785,7 @@ fn threads_support() { fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) { let rdr = std::io::Cursor::new(&buf); - iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); + iter_directives(TestMode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 9819079e284f9..be82f8cb480d4 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -39,8 +39,8 @@ use walkdir::WalkDir; use self::directives::{EarlyProps, make_test_description}; use crate::common::{ - CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path, - output_base_dir, output_relative_path, + CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS, + expected_output_path, output_base_dir, output_relative_path, }; use crate::directives::DirectivesCache; use crate::executor::{CollectedTest, ColorConfig, OutputFormat}; @@ -268,7 +268,7 @@ pub fn parse_config(args: Vec) -> Config { let with_rustc_debug_assertions = matches.opt_present("with-rustc-debug-assertions"); let with_std_debug_assertions = matches.opt_present("with-std-debug-assertions"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); - let has_html_tidy = if mode == Mode::Rustdoc { + let has_html_tidy = if mode == TestMode::Rustdoc { Command::new("tidy") .arg("--version") .stdout(Stdio::null()) @@ -279,7 +279,7 @@ pub fn parse_config(args: Vec) -> Config { false }; let has_enzyme = matches.opt_present("has-enzyme"); - let filters = if mode == Mode::RunMake { + let filters = if mode == TestMode::RunMake { matches .free .iter() @@ -545,7 +545,7 @@ pub fn run_tests(config: Arc) { unsafe { env::set_var("TARGET", &config.target) }; let mut configs = Vec::new(); - if let Mode::DebugInfo = config.mode { + if let TestMode::DebugInfo = config.mode { // Debugging emscripten code doesn't make sense today if !config.target.contains("emscripten") { match config.debugger { @@ -783,7 +783,7 @@ fn collect_tests_from_dir( } // For run-make tests, a "test file" is actually a directory that contains an `rmake.rs`. - if cx.config.mode == Mode::RunMake { + if cx.config.mode == TestMode::RunMake { let mut collector = TestCollector::new(); if dir.join("rmake.rs").exists() { let paths = TestPaths { @@ -869,7 +869,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te // For run-make tests, each "test file" is actually a _directory_ containing an `rmake.rs`. But // for the purposes of directive parsing, we want to look at that recipe file, not the directory // itself. - let test_path = if cx.config.mode == Mode::RunMake { + let test_path = if cx.config.mode == TestMode::RunMake { testpaths.file.join("rmake.rs") } else { testpaths.file.clone() @@ -884,7 +884,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te // - Incremental tests inherently can't run their revisions in parallel, so // we treat them like non-revisioned tests here. Incremental revisions are // handled internally by `runtest::run` instead. - let revisions = if early_props.revisions.is_empty() || cx.config.mode == Mode::Incremental { + let revisions = if early_props.revisions.is_empty() || cx.config.mode == TestMode::Incremental { vec![None] } else { early_props.revisions.iter().map(|r| Some(r.as_str())).collect() @@ -1116,11 +1116,11 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet) { } pub fn early_config_check(config: &Config) { - if !config.has_html_tidy && config.mode == Mode::Rustdoc { + if !config.has_html_tidy && config.mode == TestMode::Rustdoc { warning!("`tidy` (html-tidy.org) is not installed; diffs will not be generated"); } - if !config.profiler_runtime && config.mode == Mode::CoverageRun { + if !config.profiler_runtime && config.mode == TestMode::CoverageRun { let actioned = if config.bless { "blessed" } else { "checked" }; warning!("profiler runtime is not available, so `.coverage` files won't be {actioned}"); help!("try setting `profiler = true` in the `[build]` section of `bootstrap.toml`"); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 933a32392bddf..dcfd15ad19132 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -349,7 +349,7 @@ impl<'test> TestCx<'test> { if proc_res.status.success() { { self.error(&format!("{} test did not emit an error", self.config.mode)); - if self.config.mode == crate::common::Mode::Ui { + if self.config.mode == crate::common::TestMode::Ui { println!("note: by default, ui tests are expected not to compile"); } proc_res.fatal(None, || ()); diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index 6461f38f527b4..dd9be8d5e7db7 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -114,7 +114,7 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse if let Some(librs) = find_librs(entry.path()) { let compiletest_c = compiletest::common::Config { edition: None, - mode: compiletest::common::Mode::Rustdoc, + mode: compiletest::common::TestMode::Rustdoc, ..Default::default() }; From b9ae117199fd70b860088105aaaca94582eac8a4 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 16:17:10 +0800 Subject: [PATCH 24/25] Do not glob-reexport `TestMode` variants I would like to introduce `TestSuite` over stringly-typed test suite names, and some test suite names are the same as test modes, which can make this very confusing. --- src/tools/compiletest/src/common.rs | 5 +- src/tools/compiletest/src/directives.rs | 2 +- src/tools/compiletest/src/runtest.rs | 111 +++++++++++++----------- 3 files changed, 65 insertions(+), 53 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index d621ee8de4fbd..f3a5b4145fd93 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -8,7 +8,6 @@ use camino::{Utf8Path, Utf8PathBuf}; use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; -pub use self::TestMode::*; use crate::executor::{ColorConfig, OutputFormat}; use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum}; @@ -39,7 +38,7 @@ impl TestMode { // Pretty-printing tests could run concurrently, and if they do, // they need to keep their output segregated. match self { - Pretty => ".pretty", + TestMode::Pretty => ".pretty", _ => "", } } @@ -48,7 +47,7 @@ impl TestMode { // Coverage tests use the same test files for multiple test modes, // so each mode should have a separate output directory. match self { - CoverageMap | CoverageRun => self.to_str(), + TestMode::CoverageMap | TestMode::CoverageRun => self.to_str(), _ => "", } } diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index ddd04376082c7..7fadb4dae2a1d 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1443,7 +1443,7 @@ pub(crate) fn make_test_description( // since we run the pretty printer across all tests by default. // If desired, we could add a `should-fail-pretty` annotation. let should_panic = match config.mode { - crate::common::Pretty => ShouldPanic::No, + TestMode::Pretty => ShouldPanic::No, _ if should_fail => ShouldPanic::Yes, _ => ShouldPanic::No, }; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index dcfd15ad19132..12111e9c6ef54 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -16,11 +16,10 @@ use regex::{Captures, Regex}; use tracing::*; use crate::common::{ - Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes, - DebugInfo, Debugger, FailMode, Incremental, MirOpt, PassMode, Pretty, RunMake, Rustdoc, - RustdocJs, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, - UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir, - output_base_dir, output_base_name, output_testname_unique, + CompareMode, Config, Debugger, FailMode, PassMode, TestMode, TestPaths, UI_EXTENSIONS, + UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, + expected_output_path, incremental_dir, output_base_dir, output_base_name, + output_testname_unique, }; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; use crate::directives::TestProps; @@ -154,7 +153,7 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { cx.init_incremental_test(); } - if config.mode == Incremental { + if config.mode == TestMode::Incremental { // Incremental tests are special because they cannot be run in // parallel. assert!(!props.revisions.is_empty(), "Incremental tests require revisions."); @@ -203,7 +202,7 @@ pub fn compute_stamp_hash(config: &Config) -> String { None => {} } - if let Ui = config.mode { + if config.mode == TestMode::Ui { config.force_pass_mode.hash(&mut hash); } @@ -251,25 +250,28 @@ impl<'test> TestCx<'test> { /// Code executed for each revision in turn (or, if there are no /// revisions, exactly once, with revision == None). fn run_revision(&self) { - if self.props.should_ice && self.config.mode != Incremental && self.config.mode != Crashes { + if self.props.should_ice + && self.config.mode != TestMode::Incremental + && self.config.mode != TestMode::Crashes + { self.fatal("cannot use should-ice in a test that is not cfail"); } match self.config.mode { - Pretty => self.run_pretty_test(), - DebugInfo => self.run_debuginfo_test(), - Codegen => self.run_codegen_test(), - Rustdoc => self.run_rustdoc_test(), - RustdocJson => self.run_rustdoc_json_test(), - CodegenUnits => self.run_codegen_units_test(), - Incremental => self.run_incremental_test(), - RunMake => self.run_rmake_test(), - Ui => self.run_ui_test(), - MirOpt => self.run_mir_opt_test(), - Assembly => self.run_assembly_test(), - RustdocJs => self.run_rustdoc_js_test(), - CoverageMap => self.run_coverage_map_test(), // see self::coverage - CoverageRun => self.run_coverage_run_test(), // see self::coverage - Crashes => self.run_crash_test(), + TestMode::Pretty => self.run_pretty_test(), + TestMode::DebugInfo => self.run_debuginfo_test(), + TestMode::Codegen => self.run_codegen_test(), + TestMode::Rustdoc => self.run_rustdoc_test(), + TestMode::RustdocJson => self.run_rustdoc_json_test(), + TestMode::CodegenUnits => self.run_codegen_units_test(), + TestMode::Incremental => self.run_incremental_test(), + TestMode::RunMake => self.run_rmake_test(), + TestMode::Ui => self.run_ui_test(), + TestMode::MirOpt => self.run_mir_opt_test(), + TestMode::Assembly => self.run_assembly_test(), + TestMode::RustdocJs => self.run_rustdoc_js_test(), + TestMode::CoverageMap => self.run_coverage_map_test(), // see self::coverage + TestMode::CoverageRun => self.run_coverage_run_test(), // see self::coverage + TestMode::Crashes => self.run_crash_test(), } } @@ -279,9 +281,13 @@ impl<'test> TestCx<'test> { fn should_run(&self, pm: Option) -> WillExecute { let test_should_run = match self.config.mode { - Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true, - MirOpt if pm == Some(PassMode::Run) => true, - Ui | MirOpt => false, + TestMode::Ui + if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => + { + true + } + TestMode::MirOpt if pm == Some(PassMode::Run) => true, + TestMode::Ui | TestMode::MirOpt => false, mode => panic!("unimplemented for mode {:?}", mode), }; if test_should_run { self.run_if_enabled() } else { WillExecute::No } @@ -293,17 +299,17 @@ impl<'test> TestCx<'test> { fn should_run_successfully(&self, pm: Option) -> bool { match self.config.mode { - Ui | MirOpt => pm == Some(PassMode::Run), + TestMode::Ui | TestMode::MirOpt => pm == Some(PassMode::Run), mode => panic!("unimplemented for mode {:?}", mode), } } fn should_compile_successfully(&self, pm: Option) -> bool { match self.config.mode { - RustdocJs => true, - Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build), - Crashes => false, - Incremental => { + TestMode::RustdocJs => true, + TestMode::Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build), + TestMode::Crashes => false, + TestMode::Incremental => { let revision = self.revision.expect("incremental tests require a list of revisions"); if revision.starts_with("cpass") @@ -892,7 +898,9 @@ impl<'test> TestCx<'test> { fn should_emit_metadata(&self, pm: Option) -> Emit { match (pm, self.props.fail_mode, self.config.mode) { - (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata, + (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), TestMode::Ui) => { + Emit::Metadata + } _ => Emit::None, } } @@ -926,7 +934,7 @@ impl<'test> TestCx<'test> { }; let allow_unused = match self.config.mode { - Ui => { + TestMode::Ui => { // UI tests tend to have tons of unused code as // it's just testing various pieces of the compile, but we don't // want to actually assert warnings about all this code. Instead @@ -1021,7 +1029,7 @@ impl<'test> TestCx<'test> { .args(&self.props.compile_flags) .args(&self.props.doc_flags); - if self.config.mode == RustdocJson { + if self.config.mode == TestMode::RustdocJson { rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options"); } @@ -1372,7 +1380,7 @@ impl<'test> TestCx<'test> { || self.is_vxworks_pure_static() || self.config.target.contains("bpf") || !self.config.target_cfg().dynamic_linking - || matches!(self.config.mode, CoverageMap | CoverageRun) + || matches!(self.config.mode, TestMode::CoverageMap | TestMode::CoverageRun) { // We primarily compile all auxiliary libraries as dynamic libraries // to avoid code size bloat and large binaries as much as possible @@ -1562,14 +1570,14 @@ impl<'test> TestCx<'test> { rustc.args(&["-Z", "incremental-verify-ich"]); } - if self.config.mode == CodegenUnits { + if self.config.mode == TestMode::CodegenUnits { rustc.args(&["-Z", "human_readable_cgu_names"]); } } if self.config.optimize_tests && !is_rustdoc { match self.config.mode { - Ui => { + TestMode::Ui => { // If optimize-tests is true we still only want to optimize tests that actually get // executed and that don't specify their own optimization levels. // Note: aux libs don't have a pass-mode, so they won't get optimized @@ -1585,8 +1593,8 @@ impl<'test> TestCx<'test> { rustc.arg("-O"); } } - DebugInfo => { /* debuginfo tests must be unoptimized */ } - CoverageMap | CoverageRun => { + TestMode::DebugInfo => { /* debuginfo tests must be unoptimized */ } + TestMode::CoverageMap | TestMode::CoverageRun => { // Coverage mappings and coverage reports are affected by // optimization level, so they ignore the optimize-tests // setting and set an optimization level in their mode's @@ -1607,7 +1615,7 @@ impl<'test> TestCx<'test> { }; match self.config.mode { - Incremental => { + TestMode::Incremental => { // If we are extracting and matching errors in the new // fashion, then you want JSON mode. Old-skool error // patterns still match the raw compiler output. @@ -1620,7 +1628,7 @@ impl<'test> TestCx<'test> { rustc.arg("-Zui-testing"); rustc.arg("-Zdeduplicate-diagnostics=no"); } - Ui => { + TestMode::Ui => { if !self.props.compile_flags.iter().any(|s| s.starts_with("--error-format")) { rustc.args(&["--error-format", "json"]); rustc.args(&["--json", "future-incompat"]); @@ -1633,7 +1641,7 @@ impl<'test> TestCx<'test> { // FIXME: use this for other modes too, for perf? rustc.arg("-Cstrip=debuginfo"); } - MirOpt => { + TestMode::MirOpt => { // We check passes under test to minimize the mir-opt test dump // if files_for_miropt_test parses the passes, we dump only those passes // otherwise we conservatively pass -Zdump-mir=all @@ -1663,7 +1671,7 @@ impl<'test> TestCx<'test> { set_mir_dump_dir(&mut rustc); } - CoverageMap => { + TestMode::CoverageMap => { rustc.arg("-Cinstrument-coverage"); // These tests only compile to LLVM IR, so they don't need the // profiler runtime to be present. @@ -1673,23 +1681,28 @@ impl<'test> TestCx<'test> { // by `compile-flags`. rustc.arg("-Copt-level=2"); } - CoverageRun => { + TestMode::CoverageRun => { rustc.arg("-Cinstrument-coverage"); // Coverage reports are sometimes sensitive to optimizations, // and the current snapshots assume `opt-level=2` unless // overridden by `compile-flags`. rustc.arg("-Copt-level=2"); } - Assembly | Codegen => { + TestMode::Assembly | TestMode::Codegen => { rustc.arg("-Cdebug-assertions=no"); } - Crashes => { + TestMode::Crashes => { set_mir_dump_dir(&mut rustc); } - CodegenUnits => { + TestMode::CodegenUnits => { rustc.arg("-Zprint-mono-items"); } - Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | RustdocJs => { + TestMode::Pretty + | TestMode::DebugInfo + | TestMode::Rustdoc + | TestMode::RustdocJson + | TestMode::RunMake + | TestMode::RustdocJs => { // do not use JSON output } } @@ -1962,7 +1975,7 @@ impl<'test> TestCx<'test> { /// The revision, ignored for incremental compilation since it wants all revisions in /// the same directory. fn safe_revision(&self) -> Option<&str> { - if self.config.mode == Incremental { None } else { self.revision } + if self.config.mode == TestMode::Incremental { None } else { self.revision } } /// Gets the absolute path to the directory where all output for the given From 6f8a7f00005c8b1c13c0fc0f903f0f0013530c14 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 18:59:23 +0800 Subject: [PATCH 25/25] Make rustdoc-gui-test dummy compiletest config purpose explicit --- src/tools/compiletest/src/common.rs | 101 +++++++++++++++++++++++++ src/tools/rustdoc-gui-test/src/main.rs | 6 +- 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index f3a5b4145fd93..849f44031b7b4 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -604,6 +604,107 @@ pub struct Config { } impl Config { + /// Incomplete config intended for `src/tools/rustdoc-gui-test` **only** as + /// `src/tools/rustdoc-gui-test` wants to reuse `compiletest`'s directive -> test property + /// handling for `//@ {compile,run}-flags`, do not use for any other purpose. + /// + /// FIXME(#143827): this setup feels very hacky. It so happens that `tests/rustdoc-gui/` + /// **only** uses `//@ {compile,run}-flags` for now and not any directives that actually rely on + /// info that is assumed available in a fully populated [`Config`]. + pub fn incomplete_for_rustdoc_gui_test() -> Config { + // FIXME(#143827): spelling this out intentionally, because this is questionable. + // + // For instance, `//@ ignore-stage1` will not work at all. + Config { + mode: TestMode::Rustdoc, + + // Dummy values. + edition: Default::default(), + bless: Default::default(), + fail_fast: Default::default(), + compile_lib_path: Utf8PathBuf::default(), + run_lib_path: Utf8PathBuf::default(), + rustc_path: Utf8PathBuf::default(), + cargo_path: Default::default(), + stage0_rustc_path: Default::default(), + rustdoc_path: Default::default(), + coverage_dump_path: Default::default(), + python: Default::default(), + jsondocck_path: Default::default(), + jsondoclint_path: Default::default(), + llvm_filecheck: Default::default(), + llvm_bin_dir: Default::default(), + run_clang_based_tests_with: Default::default(), + src_root: Utf8PathBuf::default(), + src_test_suite_root: Utf8PathBuf::default(), + build_root: Utf8PathBuf::default(), + build_test_suite_root: Utf8PathBuf::default(), + sysroot_base: Utf8PathBuf::default(), + stage: Default::default(), + stage_id: String::default(), + suite: Default::default(), + debugger: Default::default(), + run_ignored: Default::default(), + with_rustc_debug_assertions: Default::default(), + with_std_debug_assertions: Default::default(), + filters: Default::default(), + skip: Default::default(), + filter_exact: Default::default(), + force_pass_mode: Default::default(), + run: Default::default(), + runner: Default::default(), + host_rustcflags: Default::default(), + target_rustcflags: Default::default(), + rust_randomized_layout: Default::default(), + optimize_tests: Default::default(), + target: Default::default(), + host: Default::default(), + cdb: Default::default(), + cdb_version: Default::default(), + gdb: Default::default(), + gdb_version: Default::default(), + lldb_version: Default::default(), + llvm_version: Default::default(), + system_llvm: Default::default(), + android_cross_path: Default::default(), + adb_path: Default::default(), + adb_test_dir: Default::default(), + adb_device_status: Default::default(), + lldb_python_dir: Default::default(), + verbose: Default::default(), + format: Default::default(), + color: Default::default(), + remote_test_client: Default::default(), + compare_mode: Default::default(), + rustfix_coverage: Default::default(), + has_html_tidy: Default::default(), + has_enzyme: Default::default(), + channel: Default::default(), + git_hash: Default::default(), + cc: Default::default(), + cxx: Default::default(), + cflags: Default::default(), + cxxflags: Default::default(), + ar: Default::default(), + target_linker: Default::default(), + host_linker: Default::default(), + llvm_components: Default::default(), + nodejs: Default::default(), + npm: Default::default(), + force_rerun: Default::default(), + only_modified: Default::default(), + target_cfgs: Default::default(), + builtin_cfg_names: Default::default(), + supported_crate_types: Default::default(), + nocapture: Default::default(), + nightly_branch: Default::default(), + git_merge_commit_email: Default::default(), + profiler_runtime: Default::default(), + diff_command: Default::default(), + minicore_path: Default::default(), + } + } + /// FIXME: this run scheme is... confusing. pub fn run_enabled(&self) -> bool { self.run.unwrap_or_else(|| { diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index dd9be8d5e7db7..0e35861fbf737 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -112,11 +112,7 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse .current_dir(path); if let Some(librs) = find_librs(entry.path()) { - let compiletest_c = compiletest::common::Config { - edition: None, - mode: compiletest::common::TestMode::Rustdoc, - ..Default::default() - }; + let compiletest_c = compiletest::common::Config::incomplete_for_rustdoc_gui_test(); let test_props = TestProps::from_file( &camino::Utf8PathBuf::try_from(librs).unwrap(),