From f1b5a5638ec3aba301dc5a50daccb4c1ed69ac78 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Thu, 3 Jul 2025 08:57:32 +0000 Subject: [PATCH 01/64] wrapping shift: remove first bitmask and table --- library/core/src/num/wrapping.rs | 48 ++++---------------------------- 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 55fa91d0b9f4..c460f38bd2e4 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -94,9 +94,9 @@ macro_rules! sh_impl_signed { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shr((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(-other as u32)) } else { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } } @@ -119,9 +119,9 @@ macro_rules! sh_impl_signed { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { if other < 0 { - Wrapping(self.0.wrapping_shl((-other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(-other as u32)) } else { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } } @@ -147,7 +147,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shl(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shl(other as u32)) } } forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, @@ -168,7 +168,7 @@ macro_rules! sh_impl_unsigned { #[inline] fn shr(self, other: $f) -> Wrapping<$t> { - Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) + Wrapping(self.0.wrapping_shr(other as u32)) } } forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, @@ -1052,39 +1052,3 @@ macro_rules! wrapping_int_impl_unsigned { } wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 } - -mod shift_max { - #![allow(non_upper_case_globals)] - - #[cfg(target_pointer_width = "16")] - mod platform { - pub(crate) const usize: u32 = super::u16; - pub(crate) const isize: u32 = super::i16; - } - - #[cfg(target_pointer_width = "32")] - mod platform { - pub(crate) const usize: u32 = super::u32; - pub(crate) const isize: u32 = super::i32; - } - - #[cfg(target_pointer_width = "64")] - mod platform { - pub(crate) const usize: u32 = super::u64; - pub(crate) const isize: u32 = super::i64; - } - - pub(super) const i8: u32 = (1 << 3) - 1; - pub(super) const i16: u32 = (1 << 4) - 1; - pub(super) const i32: u32 = (1 << 5) - 1; - pub(super) const i64: u32 = (1 << 6) - 1; - pub(super) const i128: u32 = (1 << 7) - 1; - pub(super) use self::platform::isize; - - pub(super) const u8: u32 = i8; - pub(super) const u16: u32 = i16; - pub(super) const u32: u32 = i32; - pub(super) const u64: u32 = i64; - pub(super) const u128: u32 = i128; - pub(super) use self::platform::usize; -} From 148a220e38f0b2ba4ec8014d0c1e83ca6d52d47e Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Fri, 4 Jul 2025 13:10:34 +0200 Subject: [PATCH 02/64] remote-test-client: Exit code `128 + ` instead of `3` If the remote process is terminated by a signal, make `remote-test-client` exit with the code `128 + ` instead of always `3`. This follows common practice among tools such as bash [^1]: > When a command terminates on a fatal signal whose number is N, Bash uses the > value 128+N as the exit status. It also allows us to differentiate between `run-pass` and `run-crash` ui tests without special case code in compiletest for that when `remote-test-client` is used. [^1]: https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html --- src/tools/remote-test-client/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index bda08423487b..b9741431b503 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -335,7 +335,9 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { std::process::exit(code); } else { println!("died due to signal {}", code); - std::process::exit(3); + // Behave like bash and other tools and exit with 128 + the signal + // number. That way we can avoid special case code in other places. + std::process::exit(128 + code); } } From 925789456aa0bb112d8ab2fe3f31f4f7317f463b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Jul 2025 18:12:31 +0200 Subject: [PATCH 03/64] miri: fix out-of-bounds error for ptrs with negative offsets --- compiler/rustc_const_eval/messages.ftl | 27 ++++++++++--------- .../out_of_bounds_read_neg_offset.rs | 6 +++++ .../out_of_bounds_read_neg_offset.stderr | 21 +++++++++++++++ .../ptr_offset_out_of_bounds_neg2.rs | 6 +++++ .../ptr_offset_out_of_bounds_neg2.stderr | 20 ++++++++++++++ tests/ui/consts/offset_ub.rs | 14 +++++----- tests/ui/consts/offset_ub.stderr | 6 ++--- 7 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs create mode 100644 src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 22a1894ee720..dd12afb28532 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -294,19 +294,22 @@ const_eval_pointer_arithmetic_overflow = overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` const_eval_pointer_out_of_bounds = - {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg -> - [false] {$alloc_size_minus_ptr_offset -> - [0] is at or beyond the end of the allocation of size {$alloc_size -> - [1] 1 byte - *[x] {$alloc_size} bytes + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$ptr_offset_is_neg -> + [true] points to before the beginning of the allocation + *[false] {$inbounds_size_is_neg -> + [false] {$alloc_size_minus_ptr_offset -> + [0] is at or beyond the end of the allocation of size {$alloc_size -> + [1] 1 byte + *[x] {$alloc_size} bytes + } + [1] is only 1 byte from the end of the allocation + *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + } + *[true] {$ptr_offset_abs -> + [0] is at the beginning of the allocation + *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation } - [1] is only 1 byte from the end of the allocation - *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation - } - *[true] {$ptr_offset_abs -> - [0] is at the beginning of the allocation - *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation - } + } } const_eval_pointer_use_after_free = diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs new file mode 100644 index 000000000000..107a3db91d85 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs @@ -0,0 +1,6 @@ +fn main() { + let v: Vec = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; //~ ERROR: before the beginning of the allocation + panic!("this should never print: {}", x); +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr new file mode 100644 index 000000000000..5c37caa1ebf0 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC-0x5 which points to before the beginning of the allocation + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_byte_sub(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + | +LL | let v: Vec = vec![1, 2]; + | ^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/dangling_pointers/out_of_bounds_read_neg_offset.rs:LL:CC + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs new file mode 100644 index 000000000000..0085e2af3673 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs @@ -0,0 +1,6 @@ +fn main() { + let v = [0i8; 4]; + let x = &v as *const i8; + let x = unsafe { x.wrapping_offset(-1).offset(-1) }; //~ERROR: before the beginning of the allocation + panic!("this should never print: {:?}", x); +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr new file mode 100644 index 000000000000..495aaf8d40ee --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC-0x1 which points to before the beginning of the allocation + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let x = unsafe { x.wrapping_offset(-1).offset(-1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + | +LL | let v = [0i8; 4]; + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at tests/fail/intrinsics/ptr_offset_out_of_bounds_neg2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index 8c52586c485f..98a50156a948 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -5,17 +5,17 @@ use std::ptr; //@ normalize-stderr: "\d+ bytes" -> "$$BYTES bytes" -pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR -pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR -pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR +pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~ ERROR: is at the beginning of the allocation +pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~ ERROR: only 1 byte from the end of the allocation +pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~ ERROR: only 100 bytes from the end of the allocation -pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR -pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR +pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~ ERROR: does not fit in an `isize` +pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~ ERROR: does not fit in an `isize` pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~ ERROR pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~ ERROR -pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR +pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; //~ ERROR: before the beginning of the allocation -pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR +pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~ ERROR: at or beyond the end of the allocation pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; //~ ERROR // Make sure that we don't panic when computing abs(offset*size_of::()) diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index 255583ce91c5..d92ca09223de 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -40,11 +40,11 @@ error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `UNDERFLOW_ADDRESS_SPACE` failed here -error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation +error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which points to before the beginning of the allocation --> $DIR/offset_ub.rs:16:49 | -LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here +LL | ...*const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `NEGATIVE_OFFSET` failed here error[E0080]: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes --> $DIR/offset_ub.rs:18:50 From cfb66e5e88a4f5333b328df0b6363ded674f92b4 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 05:53:40 -0400 Subject: [PATCH 04/64] Consolidate infinity tests --- library/coretests/tests/floats/f128.rs | 12 ------------ library/coretests/tests/floats/f16.rs | 12 ------------ library/coretests/tests/floats/f32.rs | 12 ------------ library/coretests/tests/floats/f64.rs | 12 ------------ library/coretests/tests/floats/mod.rs | 18 ++++++++++++++++++ 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 38df09a91c10..1b7ac82c1e9c 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -55,18 +55,6 @@ fn test_num_f128() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f128 = f128::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f128 = f128::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index f6749d796cca..e69fe4d70bc7 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -51,18 +51,6 @@ fn test_num_f16() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_infinity() { - let inf: f16 = f16::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f16 = f16::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index f5d5723fea45..1efa8b3fdd5e 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -35,18 +35,6 @@ fn test_num_f32() { super::test_num(10f32, 2f32); } -#[test] -fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f32 = f32::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 34af87c241e9..9771abd2fe31 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -30,18 +30,6 @@ fn test_num_f64() { super::test_num(10f64, 2f64); } -#[test] -fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); -} - #[test] fn test_neg_infinity() { let neg_inf: f64 = f64::NEG_INFINITY; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 36743a7d6df9..9fe74090f158 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -273,6 +273,24 @@ float_test! { } } +float_test! { + name: infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let inf: Float = Float::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert!(matches!(inf.classify(), Fp::Infinite)); + } +} + float_test! { name: min, attrs: { From c5e67b48ef0b073c07a57557d0dd205c099fc56e Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:20:28 -0400 Subject: [PATCH 05/64] Consolidate test_num tests --- library/coretests/tests/floats/f128.rs | 15 -------- library/coretests/tests/floats/f16.rs | 5 --- library/coretests/tests/floats/f32.rs | 5 --- library/coretests/tests/floats/f64.rs | 5 --- library/coretests/tests/floats/mod.rs | 53 ++++++++++++++++---------- library/coretests/tests/lib.rs | 1 + 6 files changed, 34 insertions(+), 50 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 1b7ac82c1e9c..508d30963a55 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,7 +1,6 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -use core::ops::{Add, Div, Mul, Sub}; use std::f128::consts; use std::num::FpCategory as Fp; @@ -38,20 +37,6 @@ const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; /// Second pattern over the mantissa const NAN_MASK2: u128 = 0x00005555555555555555555555555555; -#[test] -fn test_num_f128() { - // FIXME(f16_f128): replace with a `test_num` call once the required `fmodl`/`fmodf128` - // function is available on all platforms. - let ten = 10f128; - let two = 2f128; - assert_biteq!(ten.add(two), ten + two); - assert_biteq!(ten.sub(two), ten - two); - assert_biteq!(ten.mul(two), ten * two); - assert_biteq!(ten.div(two), ten / two); - #[cfg(any(miri, target_has_reliable_f128_math))] - assert_biteq!(core::ops::Rem::rem(ten, two), ten % two); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index e69fe4d70bc7..426411f67372 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -43,11 +43,6 @@ const NAN_MASK1: u16 = 0x02aa; /// Second pattern over the mantissa const NAN_MASK2: u16 = 0x0155; -#[test] -fn test_num_f16() { - super::test_num(10f16, 2f16); -} - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 1efa8b3fdd5e..4fe21975d41f 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,11 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_num_f32() { - super::test_num(10f32, 2f32); -} - #[test] fn test_neg_infinity() { let neg_inf: f32 = f32::NEG_INFINITY; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 9771abd2fe31..7016f3643c88 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,11 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_num_f64() { - super::test_num(10f64, 2f64); -} - #[test] fn test_neg_infinity() { let neg_inf: f64 = f64::NEG_INFINITY; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 9fe74090f158..a746e4bf40d3 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,4 +1,3 @@ -use std::fmt; use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; @@ -190,6 +189,8 @@ macro_rules! float_test { use super::Approx; #[allow(unused)] use std::num::FpCategory as Fp; + #[allow(unused)] + use std::ops::{Add, Div, Mul, Rem, Sub}; // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] use $crate::floats::{ @@ -229,30 +230,42 @@ macro_rules! float_test { }; } -/// Helper function for testing numeric operations -pub fn test_num(ten: T, two: T) -where - T: PartialEq - + Add - + Sub - + Mul - + Div - + Rem - + fmt::Debug - + Copy, -{ - assert_eq!(ten.add(two), ten + two); - assert_eq!(ten.sub(two), ten - two); - assert_eq!(ten.mul(two), ten * two); - assert_eq!(ten.div(two), ten / two); - assert_eq!(ten.rem(two), ten % two); -} - mod f128; mod f16; mod f32; mod f64; +float_test! { + name: num, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.add(two), ten + two); + assert_biteq!(ten.sub(two), ten - two); + assert_biteq!(ten.mul(two), ten * two); + assert_biteq!(ten.div(two), ten / two); + } +} + +// FIXME(f16_f128): merge into `num` once the required `fmodl`/`fmodf128` function is available on +// all platforms. +float_test! { + name: num_rem, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + let two: Float = 2.0; + let ten: Float = 10.0; + assert_biteq!(ten.rem(two), ten % two); + } +} + float_test! { name: nan, attrs: { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index fdef736c0c0f..e2249bd7f6a1 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(const_destruct)] #![feature(const_eval_select)] #![feature(const_float_round_methods)] +#![feature(const_ops)] #![feature(const_ref_cell)] #![feature(const_trait_impl)] #![feature(core_float_math)] From c2e6b39474beacf2be7313326f0a06e3d7f85f04 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:10:39 -0400 Subject: [PATCH 06/64] Consolidate neg_infinity tests --- library/coretests/tests/floats/f128.rs | 12 ------------ library/coretests/tests/floats/f16.rs | 12 ------------ library/coretests/tests/floats/f32.rs | 12 ------------ library/coretests/tests/floats/f64.rs | 12 ------------ library/coretests/tests/floats/mod.rs | 18 ++++++++++++++++++ 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 508d30963a55..db6441df32bc 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,18 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_infinity() { - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f128 = 0.0f128; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 426411f67372..051737c34c31 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,18 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_infinity() { - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f16 = 0.0f16; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 4fe21975d41f..0cf9ef042a0d 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,18 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f32 = 0.0f32; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 7016f3643c88..1e995d77e3c8 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,18 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); -} - #[test] fn test_zero() { let zero: f64 = 0.0f64; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index a746e4bf40d3..ed30aae44115 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -304,6 +304,24 @@ float_test! { } } +float_test! { + name: neg_infinity, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_inf: Float = Float::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + } +} + float_test! { name: min, attrs: { From 0c01322ec6578644108fb66b279f18f3d5382368 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:26:39 -0400 Subject: [PATCH 07/64] Consolidate zero tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 19 +++++++++++++++++++ 5 files changed, 19 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index db6441df32bc..85e9bfef125b 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_zero() { - let zero: f128 = 0.0f128; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f128 = -0.0; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 051737c34c31..fced642eb132 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_zero() { - let zero: f16 = 0.0f16; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f16 = -0.0; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 0cf9ef042a0d..23e98a9589c0 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_zero() { - let zero: f32 = 0.0f32; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f32 = -0.0; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 1e995d77e3c8..739ff8a7aa7b 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_zero() { - let zero: f64 = 0.0f64; - assert_biteq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); -} - #[test] fn test_neg_zero() { let neg_zero: f64 = -0.0; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index ed30aae44115..75dbe4a9d6db 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -322,6 +322,25 @@ float_test! { } } +float_test! { + name: zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let zero: Float = 0.0; + assert_biteq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert!(matches!(zero.classify(), Fp::Zero)); + } +} + float_test! { name: min, attrs: { From fc01eed02444e412761ac1b5b723d45f443800fb Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:31:29 -0400 Subject: [PATCH 08/64] Consolidate negative zero tests --- library/coretests/tests/floats/f128.rs | 14 -------------- library/coretests/tests/floats/f16.rs | 14 -------------- library/coretests/tests/floats/f32.rs | 14 -------------- library/coretests/tests/floats/f64.rs | 14 -------------- library/coretests/tests/floats/mod.rs | 20 ++++++++++++++++++++ 5 files changed, 20 insertions(+), 56 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 85e9bfef125b..dbf4d6df6365 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,20 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_zero() { - let neg_zero: f128 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f128 = 1.0f128; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index fced642eb132..15ab57f8e7ee 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,20 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_neg_zero() { - let neg_zero: f16 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f16 = 1.0f16; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 23e98a9589c0..935bfa8b2734 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,20 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f32 = 1.0f32; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 739ff8a7aa7b..d3637dfd9d67 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,20 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert_biteq!(-0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); -} - #[test] fn test_one() { let one: f64 = 1.0f64; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 75dbe4a9d6db..006f51488dde 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -341,6 +341,26 @@ float_test! { } } +float_test! { + name: neg_zero, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let neg_zero: Float = -0.0; + assert!(0.0 == neg_zero); + assert_biteq!(-0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + } +} + float_test! { name: min, attrs: { From 868020e0594969356d1c41831c84fe68f7b514f0 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:40:10 -0400 Subject: [PATCH 09/64] Consolidate one tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 19 +++++++++++++++++++ 5 files changed, 19 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index dbf4d6df6365..289752673fe7 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_one() { - let one: f128 = 1.0f128; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 15ab57f8e7ee..3435630a4ffd 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_one() { - let one: f16 = 1.0f16; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 935bfa8b2734..5b1151aca9fe 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_one() { - let one: f32 = 1.0f32; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index d3637dfd9d67..7473fc07dbeb 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_one() { - let one: f64 = 1.0f64; - assert_biteq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); -} - #[test] fn test_is_nan() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 006f51488dde..abe827b69885 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -361,6 +361,25 @@ float_test! { } } +float_test! { + name: one, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let one: Float = 1.0; + assert_biteq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert!(matches!(one.classify(), Fp::Normal)); + } +} + float_test! { name: min, attrs: { From 1b8904c0c59a1790f38d2ddc05f4c3416030e07e Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:42:48 -0400 Subject: [PATCH 10/64] Consolidate is_nan --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 22 ++++++++++++++++++++++ 5 files changed, 22 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 289752673fe7..6a987494a6a4 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_nan() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f128.is_nan()); - assert!(!5.3f128.is_nan()); - assert!(!(-10.732f128).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 3435630a4ffd..dec371a7de94 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_nan() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f16.is_nan()); - assert!(!5.3f16.is_nan()); - assert!(!(-10.732f16).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 5b1151aca9fe..5ca6a633a97b 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 7473fc07dbeb..6dd18b25527f 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); -} - #[test] fn test_is_infinite() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index abe827b69885..613557975a20 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -380,6 +380,28 @@ float_test! { } } +float_test! { + name: is_nan, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 5.3; + let neg: Float = -10.732; + assert!(nan.is_nan()); + assert!(!zero.is_nan()); + assert!(!pos.is_nan()); + assert!(!neg.is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); + } +} + float_test! { name: min, attrs: { From e3d83679cb1a921fd50ee70dee15e57c6529abed Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:49:48 -0400 Subject: [PATCH 11/64] Consolidate is_infinite tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 22 ++++++++++++++++++++++ 5 files changed, 22 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 6a987494a6a4..7ed17731a81a 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_infinite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f128.is_infinite()); - assert!(!42.8f128.is_infinite()); - assert!(!(-109.2f128).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index dec371a7de94..ac972200c3d2 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_infinite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f16.is_infinite()); - assert!(!42.8f16.is_infinite()); - assert!(!(-109.2f16).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 5ca6a633a97b..d6a34ba2ac62 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 6dd18b25527f..cb3c57140e9e 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); -} - #[test] fn test_is_finite() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 613557975a20..3f6fe91d36e8 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -402,6 +402,28 @@ float_test! { } } +float_test! { + name: is_infinite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!zero.is_infinite()); + assert!(!pos.is_infinite()); + assert!(!neg.is_infinite()); + } +} + float_test! { name: min, attrs: { From 7dd2811b2af5beb2962d58d2f9f9b78e815a2576 Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:53:48 -0400 Subject: [PATCH 12/64] Consolidate is_finite tests --- library/coretests/tests/floats/f128.rs | 13 ------------- library/coretests/tests/floats/f16.rs | 13 ------------- library/coretests/tests/floats/f32.rs | 13 ------------- library/coretests/tests/floats/f64.rs | 13 ------------- library/coretests/tests/floats/mod.rs | 22 ++++++++++++++++++++++ 5 files changed, 22 insertions(+), 52 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 7ed17731a81a..160fe0380a73 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,19 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_finite() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f128.is_finite()); - assert!(42.8f128.is_finite()); - assert!((-109.2f128).is_finite()); -} - #[test] fn test_is_normal() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index ac972200c3d2..1b62278a9a33 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,19 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_finite() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f16.is_finite()); - assert!(42.8f16.is_finite()); - assert!((-109.2f16).is_finite()); -} - #[test] fn test_is_normal() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index d6a34ba2ac62..0aa95235fdec 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,19 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); -} - #[test] fn test_is_normal() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index cb3c57140e9e..9f30afb1fe1a 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,19 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); -} - #[test] fn test_is_normal() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 3f6fe91d36e8..b8ec82f75b8a 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -424,6 +424,28 @@ float_test! { } } +float_test! { + name: is_finite, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let pos: Float = 42.8; + let neg: Float = -109.2; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(zero.is_finite()); + assert!(pos.is_finite()); + assert!(neg.is_finite()); + } +} + float_test! { name: min, attrs: { From d2c1900086a057359bf6ae0f8a5b8f658fbc8bce Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 10:20:45 -0400 Subject: [PATCH 13/64] Consolidate is_normal tests --- library/coretests/tests/floats/f128.rs | 17 ------- library/coretests/tests/floats/f16.rs | 17 ------- library/coretests/tests/floats/f32.rs | 17 ------- library/coretests/tests/floats/f64.rs | 17 ------- library/coretests/tests/floats/mod.rs | 65 ++++++++++++++++++++------ 5 files changed, 51 insertions(+), 82 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 160fe0380a73..b741906a6e9e 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -40,23 +40,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_normal() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f128.is_normal()); - assert!(1e-4931f128.is_normal()); - assert!(!1e-4932f128.is_normal()); -} - #[test] fn test_classify() { let nan: f128 = f128::NAN; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 1b62278a9a33..da6414fc2444 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -46,23 +46,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_is_normal() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f16.is_normal()); - assert!(1e-4f16.is_normal()); - assert!(!1e-5f16.is_normal()); -} - #[test] fn test_classify() { let nan: f16 = f16::NAN; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 0aa95235fdec..3464930b72f7 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,23 +30,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); -} - #[test] fn test_classify() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 9f30afb1fe1a..917dae1b6c66 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -25,23 +25,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); -} - #[test] fn test_classify() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index b8ec82f75b8a..b1686514a122 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,27 +1,40 @@ use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Set the default tolerance for float comparison based on the type. -trait Approx { - const LIM: Self; +trait TestableFloat { + /// Set the default tolerance for float comparison based on the type. + const APPROX: Self; + const MIN_POSITIVE_NORMAL: Self; + const MAX_SUBNORMAL: Self; } -impl Approx for f16 { - const LIM: Self = 1e-3; +impl TestableFloat for f16 { + const APPROX: Self = 1e-3; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f32 { - const LIM: Self = 1e-6; + +impl TestableFloat for f32 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f64 { - const LIM: Self = 1e-6; + +impl TestableFloat for f64 { + const APPROX: Self = 1e-6; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } -impl Approx for f128 { - const LIM: Self = 1e-9; + +impl TestableFloat for f128 { + const APPROX: Self = 1e-9; + const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; + const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); } /// Determine the tolerance for values of the argument type. -const fn lim_for_ty(_x: T) -> T { - T::LIM +const fn lim_for_ty(_x: T) -> T { + T::APPROX } // We have runtime ("rt") and const versions of these macros. @@ -186,7 +199,7 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { #[allow(unused)] - use super::Approx; + use super::TestableFloat; #[allow(unused)] use std::num::FpCategory as Fp; #[allow(unused)] @@ -446,6 +459,30 @@ float_test! { } } +float_test! { + name: is_normal, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + f128: #[cfg(any(miri, target_has_reliable_f128))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one : Float = 1.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(one.is_normal()); + assert!(Float::MIN_POSITIVE_NORMAL.is_normal()); + assert!(!Float::MAX_SUBNORMAL.is_normal()); + } +} + float_test! { name: min, attrs: { From 79769f2d5babdfc8ca0c88045fdedcf312a3d83d Mon Sep 17 00:00:00 2001 From: Roger Curley Date: Thu, 10 Jul 2025 12:08:14 -0400 Subject: [PATCH 14/64] Consolidate classify tests --- library/coretests/tests/floats/f128.rs | 18 ------------------ library/coretests/tests/floats/f16.rs | 18 ------------------ library/coretests/tests/floats/f32.rs | 18 ------------------ library/coretests/tests/floats/f64.rs | 17 ----------------- library/coretests/tests/floats/mod.rs | 23 +++++++++++++++++++++++ 5 files changed, 23 insertions(+), 71 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index b741906a6e9e..36d6a20a9442 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f128)] use std::f128::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -40,23 +39,6 @@ const NAN_MASK2: u128 = 0x00005555555555555555555555555555; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_classify() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - let zero: f128 = 0.0f128; - let neg_zero: f128 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f128.classify(), Fp::Normal); - assert_eq!(1e-4931f128.classify(), Fp::Normal); - assert_eq!(1e-4932f128.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index da6414fc2444..351c008a37ba 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -2,7 +2,6 @@ #![cfg(target_has_reliable_f16)] use std::f16::consts; -use std::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -46,23 +45,6 @@ const NAN_MASK2: u16 = 0x0155; // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -fn test_classify() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - let zero: f16 = 0.0f16; - let neg_zero: f16 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f16.classify(), Fp::Normal); - assert_eq!(1e-4f16.classify(), Fp::Normal); - assert_eq!(1e-5f16.classify(), Fp::Subnormal); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 3464930b72f7..267b0e4e2943 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,6 +1,5 @@ use core::f32; use core::f32::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -30,23 +29,6 @@ const NAN_MASK2: u32 = 0x0055_5555; /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; -#[test] -fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 917dae1b6c66..735b7a765151 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,6 +1,5 @@ use core::f64; use core::f64::consts; -use core::num::FpCategory as Fp; use super::{assert_approx_eq, assert_biteq}; @@ -25,22 +24,6 @@ const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u64 = 0x0005_5555_5555_5555; -#[test] -fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); -} - #[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index b1686514a122..43431bba6954 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -483,6 +483,29 @@ float_test! { } } +float_test! { + name: classify, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + let zero: Float = 0.0; + let neg_zero: Float = -0.0; + let one: Float = 1.0; + assert!(matches!(nan.classify(), Fp::Nan)); + assert!(matches!(inf.classify(), Fp::Infinite)); + assert!(matches!(neg_inf.classify(), Fp::Infinite)); + assert!(matches!(zero.classify(), Fp::Zero)); + assert!(matches!(neg_zero.classify(), Fp::Zero)); + assert!(matches!(one.classify(), Fp::Normal)); + assert!(matches!(Float::MIN_POSITIVE_NORMAL.classify(), Fp::Normal)); + assert!(matches!(Float::MAX_SUBNORMAL.classify(), Fp::Subnormal)); + } +} + float_test! { name: min, attrs: { From afeed5067762d0a087744bda528cc3c95cb81e9a Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 20:10:36 +0800 Subject: [PATCH 15/64] Adjust `run_make_support::symbols` helpers Massage the `symbols` helpers to fill out {match all, match any} x {substring match, exact match}: | | Substring match | Exact match | |-----------|----------------------------------------|-------------------------------| | Match any | `object_contains_any_symbol_substring` | `object_contains_any_symbol` | | Match all | `object_contains_all_symbol_substring` | `object_contains_all_symbols` | As part of this, rename `any_symbol_contains` to `object_contains_any_symbol_substring` for accuracy. --- src/tools/run-make-support/src/symbols.rs | 184 +++++++++++++++--- .../symbols-helpers/rmake.rs | 92 +++++++++ .../symbols-helpers/sample.rs | 13 ++ 3 files changed, 264 insertions(+), 25 deletions(-) create mode 100644 tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs create mode 100644 tests/run-make/compiletest-self-test/symbols-helpers/sample.rs diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs index e4d244e14a4a..0e11360bd5a0 100644 --- a/src/tools/run-make-support/src/symbols.rs +++ b/src/tools/run-make-support/src/symbols.rs @@ -1,6 +1,7 @@ +use std::collections::BTreeSet; use std::path::Path; -use object::{self, Object, ObjectSymbol, SymbolIterator}; +use object::{self, Object, ObjectSymbol}; /// Given an [`object::File`], find the exported dynamic symbol names via /// [`object::Object::exports`]. This does not distinguish between which section the symbols appear @@ -14,47 +15,180 @@ pub fn exported_dynamic_symbol_names<'file>(file: &'file object::File<'file>) -> .collect() } -/// Iterate through the symbols in an object file. See [`object::Object::symbols`]. +/// Check an object file's symbols for any matching **substrings**. That is, if an object file +/// contains a symbol named `hello_world`, it will be matched against a provided `substrings` of +/// `["hello", "bar"]`. +/// +/// Returns `true` if **any** of the symbols found in the object file at `path` contain a +/// **substring** listed in `substrings`. /// /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be /// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// On Windows MSVC, the binary (e.g. `main.exe`) does not contain the symbols, but in the separate +/// PDB file instead. Furthermore, you will need to use [`crate::llvm::llvm_pdbutil`] as `object` +/// crate does not handle PDB files. #[track_caller] -pub fn with_symbol_iter(path: P, func: F) -> R +pub fn object_contains_any_symbol_substring(path: P, substrings: &[S]) -> bool where P: AsRef, - F: FnOnce(&mut SymbolIterator<'_, '_>) -> R, + S: AsRef, { let path = path.as_ref(); let blob = crate::fs::read(path); - let f = object::File::parse(&*blob) + let obj = object::File::parse(&*blob) .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); - let mut iter = f.symbols(); - func(&mut iter) + let substrings = substrings.iter().map(|s| s.as_ref()).collect::>(); + for sym in obj.symbols() { + for substring in &substrings { + if sym.name_bytes().unwrap().windows(substring.len()).any(|x| x == substring.as_bytes()) + { + return true; + } + } + } + false } -/// Check an object file's symbols for substrings. +/// Check an object file's symbols for any exact matches against those provided in +/// `candidate_symbols`. /// -/// Returns `true` if any of the symbols found in the object file at `path` contain a substring -/// listed in `substrings`. +/// Returns `true` if **any** of the symbols found in the object file at `path` contain an **exact +/// match** against those listed in `candidate_symbols`. Take care to account for (1) platform +/// differences and (2) calling convention and symbol decorations differences. /// /// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be /// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. #[track_caller] -pub fn any_symbol_contains(path: impl AsRef, substrings: &[&str]) -> bool { - with_symbol_iter(path, |syms| { - for sym in syms { - for substring in substrings { - if sym - .name_bytes() - .unwrap() - .windows(substring.len()) - .any(|x| x == substring.as_bytes()) - { - eprintln!("{:?} contains {}", sym, substring); - return true; - } +pub fn object_contains_any_symbol(path: P, candidate_symbols: &[S]) -> bool +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()).collect::>(); + for sym in obj.symbols() { + for candidate_symbol in &candidate_symbols { + if sym.name_bytes().unwrap() == candidate_symbol.as_bytes() { + return true; } } - false - }) + } + false +} + +#[derive(Debug, PartialEq)] +pub enum ContainsAllSymbolSubstringsOutcome<'a> { + Ok, + MissingSymbolSubstrings(BTreeSet<&'a str>), +} + +/// Check an object file's symbols for presence of all of provided **substrings**. That is, if an +/// object file contains symbols `["hello", "goodbye", "world"]`, it will be matched against a list +/// of `substrings` of `["he", "go"]`. In this case, `he` is a substring of `hello`, and `go` is a +/// substring of `goodbye`, so each of `substrings` was found. +/// +/// Returns `true` if **all** `substrings` were present in the names of symbols for the given object +/// file (as substrings of symbol names). +/// +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. +#[track_caller] +pub fn object_contains_all_symbol_substring<'s, P, S>( + path: P, + substrings: &'s [S], +) -> ContainsAllSymbolSubstringsOutcome<'s> +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let substrings = substrings.iter().map(|s| s.as_ref()); + let mut unmatched_symbol_substrings = BTreeSet::from_iter(substrings); + unmatched_symbol_substrings.retain(|unmatched_symbol_substring| { + for sym in obj.symbols() { + if sym + .name_bytes() + .unwrap() + .windows(unmatched_symbol_substring.len()) + .any(|x| x == unmatched_symbol_substring.as_bytes()) + { + return false; + } + } + + true + }); + + if unmatched_symbol_substrings.is_empty() { + ContainsAllSymbolSubstringsOutcome::Ok + } else { + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(unmatched_symbol_substrings) + } +} + +#[derive(Debug, PartialEq)] +pub enum ContainsAllSymbolsOutcome<'a> { + Ok, + MissingSymbols(BTreeSet<&'a str>), +} + +/// Check an object file contains all symbols provided in `candidate_symbols`. +/// +/// Returns `true` if **all** of the symbols in `candidate_symbols` are found within the object file +/// at `path` by **exact match**. Take care to account for (1) platform differences and (2) calling +/// convention and symbol decorations differences. +/// +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +/// +/// # Platform-specific behavior +/// +/// See [`object_contains_any_symbol_substring`]. +#[track_caller] +pub fn object_contains_all_symbols( + path: P, + candidate_symbols: &[S], +) -> ContainsAllSymbolsOutcome<'_> +where + P: AsRef, + S: AsRef, +{ + let path = path.as_ref(); + let blob = crate::fs::read(path); + let obj = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); + let candidate_symbols = candidate_symbols.iter().map(|s| s.as_ref()); + let mut unmatched_symbols = BTreeSet::from_iter(candidate_symbols); + unmatched_symbols.retain(|unmatched_symbol| { + for sym in obj.symbols() { + if sym.name_bytes().unwrap() == unmatched_symbol.as_bytes() { + return false; + } + } + + true + }); + + if unmatched_symbols.is_empty() { + ContainsAllSymbolsOutcome::Ok + } else { + ContainsAllSymbolsOutcome::MissingSymbols(unmatched_symbols) + } } diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs new file mode 100644 index 000000000000..73826214aac6 --- /dev/null +++ b/tests/run-make/compiletest-self-test/symbols-helpers/rmake.rs @@ -0,0 +1,92 @@ +//! `run_make_support::symbols` helpers self test. + +// Only intended as a basic smoke test, does not try to account for platform or calling convention +// specific symbol decorations. +//@ only-x86_64-unknown-linux-gnu +//@ ignore-cross-compile + +use std::collections::BTreeSet; + +use object::{Object, ObjectSymbol}; +use run_make_support::symbols::{ + ContainsAllSymbolSubstringsOutcome, ContainsAllSymbolsOutcome, + object_contains_all_symbol_substring, object_contains_all_symbols, object_contains_any_symbol, + object_contains_any_symbol_substring, +}; +use run_make_support::{object, rfs, rust_lib_name, rustc}; + +fn main() { + rustc().input("sample.rs").emit("obj").edition("2024").run(); + + // `sample.rs` has two `no_mangle` functions, `eszett` and `beta`, in addition to `main`. + // + // These two symbol names and the test substrings used below are carefully picked to make sure + // they do not overlap with `sample` and contain non-hex characters, to avoid accidentally + // matching against CGU names like `sample.dad0f15d00c84e70-cgu.0`. + + let obj_filename = "sample.o"; + let blob = rfs::read(obj_filename); + let obj = object::File::parse(&*blob).unwrap(); + eprintln!("found symbols:"); + for sym in obj.symbols() { + eprintln!("symbol = {}", sym.name().unwrap()); + } + + // `hello` contains `hel` + assert!(object_contains_any_symbol_substring(obj_filename, &["zett"])); + assert!(object_contains_any_symbol_substring(obj_filename, &["zett", "does_not_exist"])); + assert!(!object_contains_any_symbol_substring(obj_filename, &["does_not_exist"])); + + assert!(object_contains_any_symbol(obj_filename, &["eszett"])); + assert!(object_contains_any_symbol(obj_filename, &["eszett", "beta"])); + assert!(!object_contains_any_symbol(obj_filename, &["zett"])); + assert!(!object_contains_any_symbol(obj_filename, &["does_not_exist"])); + + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett"]), + ContainsAllSymbolSubstringsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "bet"]), + ContainsAllSymbolSubstringsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + assert_eq!( + object_contains_all_symbol_substring(obj_filename, &["zett", "bet", "does_not_exist"]), + ContainsAllSymbolSubstringsOutcome::MissingSymbolSubstrings(BTreeSet::from([ + "does_not_exist" + ])) + ); + + assert_eq!( + object_contains_all_symbols(obj_filename, &["eszett"]), + ContainsAllSymbolsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["eszett", "beta"]), + ContainsAllSymbolsOutcome::Ok + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["zett"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"])) + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["zett", "beta"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["zett"])) + ); + assert_eq!( + object_contains_all_symbols(obj_filename, &["does_not_exist"]), + ContainsAllSymbolsOutcome::MissingSymbols(BTreeSet::from(["does_not_exist"])) + ); +} diff --git a/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs new file mode 100644 index 000000000000..3566d2997668 --- /dev/null +++ b/tests/run-make/compiletest-self-test/symbols-helpers/sample.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] + +#[unsafe(no_mangle)] +pub extern "C" fn eszett() -> i8 { + 42 +} + +#[unsafe(no_mangle)] +pub extern "C" fn beta() -> u32 { + 1 +} + +fn main() {} From 1d0cbc6816cbc3cf069a9970a09666ed5b4aafdf Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Sat, 12 Jul 2025 21:16:46 +0800 Subject: [PATCH 16/64] Update `run-make` tests to use adjusted `symbols` helpers --- tests/run-make/fmt-write-bloat/rmake.rs | 4 ++-- tests/run-make/used/rmake.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs index 3348651d501f..b78e8f49683c 100644 --- a/tests/run-make/fmt-write-bloat/rmake.rs +++ b/tests/run-make/fmt-write-bloat/rmake.rs @@ -20,7 +20,7 @@ use run_make_support::artifact_names::bin_name; use run_make_support::env::no_debug_assertions; use run_make_support::rustc; -use run_make_support::symbols::any_symbol_contains; +use run_make_support::symbols::object_contains_any_symbol_substring; fn main() { rustc().input("main.rs").opt().run(); @@ -31,5 +31,5 @@ fn main() { // otherwise, add them to the list of symbols to deny. panic_syms.extend_from_slice(&["panicking", "panic_fmt", "pad_integral", "Display"]); } - assert!(!any_symbol_contains(bin_name("main"), &panic_syms)); + assert!(!object_contains_any_symbol_substring(bin_name("main"), &panic_syms)); } diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs index bcdb84132d3f..456321e2f56c 100644 --- a/tests/run-make/used/rmake.rs +++ b/tests/run-make/used/rmake.rs @@ -8,9 +8,9 @@ // https://rust-lang.github.io/rfcs/2386-used.html use run_make_support::rustc; -use run_make_support::symbols::any_symbol_contains; +use run_make_support::symbols::object_contains_any_symbol_substring; fn main() { rustc().opt_level("3").emit("obj").input("used.rs").run(); - assert!(any_symbol_contains("used.o", &["FOO"])); + assert!(object_contains_any_symbol_substring("used.o", &["FOO"])); } From 10866f46172e92a7949dca2e5a52b8c444a5b082 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 15:51:32 +0800 Subject: [PATCH 17/64] Fix typo in `std::vec` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c8341750f4d3..a4741f30fa5a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3695,7 +3695,7 @@ impl Vec { /// This is optimal if: /// /// * The tail (elements in the vector after `range`) is empty, - /// * or `replace_with` yields fewer or equal elements than `range`’s length + /// * or `replace_with` yields fewer or equal elements than `range`'s length /// * or the lower bound of its `size_hint()` is exact. /// /// Otherwise, a temporary vector is allocated and the tail is moved twice. From 1cab09ed9c582e7804bd0f9a6ead61129bb537d5 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:06:53 +0800 Subject: [PATCH 18/64] `std::vec`: Upgrade `debug_assert` to UB check in `set_len` Signed-off-by: xizheyin --- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/mod.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4290bb7a8a93..947df24d44f5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -153,6 +153,7 @@ #![feature(try_trait_v2)] #![feature(try_with_capacity)] #![feature(tuple_trait)] +#![feature(ub_checks)] #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a4741f30fa5a..da3d3596d192 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -64,7 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use core::{fmt, intrinsics}; +use core::{fmt, intrinsics, ub_checks}; #[stable(feature = "extract_if", since = "1.87.0")] pub use self::extract_if::ExtractIf; @@ -1950,7 +1950,11 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn set_len(&mut self, new_len: usize) { - debug_assert!(new_len <= self.capacity()); + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::set_len requires that new_len <= capacity()", + (new_len: usize = new_len, capacity: usize = self.capacity()) => new_len <= capacity + ); self.len = new_len; } From 090c177003272da7d2d3b04702f35261d3952b72 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:17:43 +0800 Subject: [PATCH 19/64] std::vec: Add UB check in `from_raw_parts_in` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index da3d3596d192..6d44681fb28b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1058,6 +1058,11 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_raw_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } } } From 48caa5f8897263da935ebdc2bbec8a95b5d3d025 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:18:56 +0800 Subject: [PATCH 20/64] std::vec: Add UB check in `from_parts_in` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6d44681fb28b..50f8cc375bfe 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1179,6 +1179,11 @@ impl Vec { #[unstable(feature = "allocator_api", reason = "new API", issue = "32838")] // #[unstable(feature = "box_vec_non_null", issue = "130364")] pub unsafe fn from_parts_in(ptr: NonNull, length: usize, capacity: usize, alloc: A) -> Self { + ub_checks::assert_unsafe_precondition!( + check_library_ub, + "Vec::from_parts_in requires that length <= capacity", + (length: usize = length, capacity: usize = capacity) => length <= capacity + ); unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } } } From 6760cd2859db68d47d62089d9805d860fb37d518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Sun, 13 Jul 2025 22:33:49 +0200 Subject: [PATCH 21/64] core: make `str::split_at_unchecked()` inline This PR adds `#[inline]` to the method `str::split_at_unchecked()`. This is done for two reasons: 1. The method is tiny, e.g. on AMD-64 (): ```asm movq %rdi, %rax subq %rcx, %rdx movq %rsi, (%rdi) addq %rcx, %rsi movq %rcx, 8(%rdi) movq %rsi, 16(%rdi) movq %rdx, 24(%rdi) retq ``` 2. More importantly, inlining the method enables further automatic optimizations. E.g. if you split at index 3, then in the compiler (rustc, llvm or both) knows that this code cannot fail, and the panicking path is omitted in the generated code: ```rust pub fn punctuation(i: &str) -> Result<(), ()> { const THREE_CHARS: &[[u8; 3]] = &[*b"<<=", *b">>=", *b"...", *b"..="]; if let Some((head, _)) = i.split_at_checked(3) && THREE_CHARS.contains(&head.as_bytes().try_into().unwrap()) { Ok(()) } else { Err(()) } } ```
Without PR ```asm playground::punctuation: subq $40, %rsp movq %rsi, %rdx movq %rdi, %rsi movb $1, %al cmpq $3, %rdx ja .LBB2_2 je .LBB2_3 .LBB2_11: addq $40, %rsp retq .LBB2_2: cmpb $-64, 3(%rsi) jl .LBB2_11 .LBB2_3: leaq 8(%rsp), %rdi movl $3, %ecx callq *core::str::::split_at_unchecked@GOTPCREL(%rip) movq 8(%rsp), %rcx movb $1, %al testq %rcx, %rcx je .LBB2_11 cmpq $3, 16(%rsp) jne .LBB2_12 movzwl (%rcx), %edx movzbl 2(%rcx), %ecx shll $16, %ecx orl %edx, %ecx cmpl $4013115, %ecx jg .LBB2_8 cmpl $3026478, %ecx je .LBB2_10 cmpl $4009518, %ecx je .LBB2_10 jmp .LBB2_11 .LBB2_8: cmpl $4013630, %ecx je .LBB2_10 cmpl $4013116, %ecx jne .LBB2_11 .LBB2_10: xorl %eax, %eax addq $40, %rsp retq .LBB2_12: leaq .Lanon.d98a7fbb86d10a97c24516e267466134.2(%rip), %rdi leaq .Lanon.d98a7fbb86d10a97c24516e267466134.1(%rip), %rcx leaq .Lanon.d98a7fbb86d10a97c24516e267466134.6(%rip), %r8 leaq 7(%rsp), %rdx movl $43, %esi callq *core::result::unwrap_failed@GOTPCREL(%rip) ```
With PR ```asm playground::punctuation: movb $1, %al cmpq $3, %rsi ja .LBB0_2 je .LBB0_3 .LBB0_9: retq .LBB0_2: cmpb $-64, 3(%rdi) jl .LBB0_9 .LBB0_3: movzwl (%rdi), %eax movzbl 2(%rdi), %ecx shll $16, %ecx orl %eax, %ecx movb $1, %al cmpl $4013115, %ecx jg .LBB0_6 cmpl $3026478, %ecx je .LBB0_8 cmpl $4009518, %ecx je .LBB0_8 jmp .LBB0_9 .LBB0_6: cmpl $4013630, %ecx je .LBB0_8 cmpl $4013116, %ecx jne .LBB0_9 .LBB0_8: xorl %eax, %eax retq ```
--- library/core/src/str/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 32a229881753..b1ce643e87cd 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -952,6 +952,7 @@ impl str { /// /// The caller must ensure that `mid` is a valid byte offset from the start /// of the string and falls on the boundary of a UTF-8 code point. + #[inline] const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) { let len = self.len(); let ptr = self.as_ptr(); From 1cac8cbde98e7b15ad24fc96af4864cdd67b9c30 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 14 Jul 2025 03:39:24 +0800 Subject: [PATCH 22/64] Add test array-type-no-semi.rs Signed-off-by: xizheyin --- tests/ui/parser/recover/array-type-no-semi.rs | 18 ++++++ .../parser/recover/array-type-no-semi.stderr | 56 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/ui/parser/recover/array-type-no-semi.rs create mode 100644 tests/ui/parser/recover/array-type-no-semi.stderr diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs new file mode 100644 index 000000000000..ae5efbaf36ca --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi.rs @@ -0,0 +1,18 @@ +// when the next token is not a semicolon, +// we should suggest to use semicolon if recovery is allowed +// See issue #143828 + +fn main() { + let x = 5; + let b: [i32, 5]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~| ERROR expected value, found builtin type `i32` [E0423] + let a: [i32, ]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~| ERROR expected value, found builtin type `i32` [E0423] + let c: [i32, x]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~| ERROR expected value, found builtin type `i32` [E0423] + let e: [i32 5]; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` +} diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr new file mode 100644 index 000000000000..84b7282b4fed --- /dev/null +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -0,0 +1,56 @@ +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + --> $DIR/array-type-no-semi.rs:7:16 + | +LL | let b: [i32, 5]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `b` + | help: use `=` if you meant to assign + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + --> $DIR/array-type-no-semi.rs:10:16 + | +LL | let a: [i32, ]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `a` + | help: use `=` if you meant to assign + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + --> $DIR/array-type-no-semi.rs:13:16 + | +LL | let c: [i32, x]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `c` + | help: use `=` if you meant to assign + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` + --> $DIR/array-type-no-semi.rs:16:17 + | +LL | let e: [i32 5]; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `e` + +error[E0423]: expected value, found builtin type `i32` + --> $DIR/array-type-no-semi.rs:7:13 + | +LL | let b: [i32, 5]; + | ^^^ not a value + +error[E0423]: expected value, found builtin type `i32` + --> $DIR/array-type-no-semi.rs:10:13 + | +LL | let a: [i32, ]; + | ^^^ not a value + +error[E0423]: expected value, found builtin type `i32` + --> $DIR/array-type-no-semi.rs:13:13 + | +LL | let c: [i32, x]; + | ^^^ not a value + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0423`. From d3d51b4fdbd6854da015f501e6566ca17cb023e5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:12:42 +0000 Subject: [PATCH 23/64] Avoid a bunch of unnecessary `unsafe` blocks in cg_llvm --- compiler/rustc_codegen_llvm/src/back/write.rs | 73 +++++++++---------- compiler/rustc_codegen_llvm/src/common.rs | 8 +- compiler/rustc_codegen_llvm/src/consts.rs | 12 ++- .../rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +- .../src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 10 +-- 8 files changed, 52 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 506286fc2559..313bf6d20a66 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -879,9 +879,7 @@ pub(crate) fn codegen( .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); let thin_bc = module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); - unsafe { - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); - } + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); } } @@ -945,7 +943,7 @@ pub(crate) fn codegen( // binaries. So we must clone the module to produce the asm output // if we are also producing object code. let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { - unsafe { llvm::LLVMCloneModule(llmod) } + llvm::LLVMCloneModule(llmod) } else { llmod }; @@ -1073,7 +1071,7 @@ pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> } /// Embed the bitcode of an LLVM module for LTO in the LLVM module itself. -unsafe fn embed_bitcode( +fn embed_bitcode( cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module, @@ -1115,43 +1113,40 @@ unsafe fn embed_bitcode( // Unfortunately, LLVM provides no way to set custom section flags. For ELF // and COFF we emit the sections using module level inline assembly for that // reason (see issue #90326 for historical background). - unsafe { - if cgcx.target_is_like_darwin - || cgcx.target_is_like_aix - || cgcx.target_arch == "wasm32" - || cgcx.target_arch == "wasm64" - { - // We don't need custom section flags, create LLVM globals. - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); - llvm::set_initializer(llglobal, llconst); - llvm::set_section(llglobal, bitcode_section_name(cgcx)); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + if cgcx.target_is_like_darwin + || cgcx.target_is_like_aix + || cgcx.target_arch == "wasm32" + || cgcx.target_arch == "wasm64" + { + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); + llvm::set_initializer(llglobal, llconst); - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = - llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); - llvm::set_initializer(llglobal, llconst); - let section = if cgcx.target_is_like_darwin { - c"__LLVM,__cmdline" - } else if cgcx.target_is_like_aix { - c".info" - } else { - c".llvmcmd" - }; - llvm::set_section(llglobal, section); - llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::set_section(llglobal, bitcode_section_name(cgcx)); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); + llvm::set_initializer(llglobal, llconst); + let section = if cgcx.target_is_like_darwin { + c"__LLVM,__cmdline" + } else if cgcx.target_is_like_aix { + c".info" } else { - // We need custom section flags, so emit module-level inline assembly. - let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; - let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::append_module_inline_asm(llmod, &asm); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::append_module_inline_asm(llmod, &asm); - } + c".llvmcmd" + }; + llvm::set_section(llglobal, section); + llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); + } else { + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::append_module_inline_asm(llmod, &asm); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + llvm::append_module_inline_asm(llmod, &asm); } } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b9b5c776d86a..f9ab96b57895 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -215,10 +215,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { bug!("symbol `{}` is already defined", sym); }); llvm::set_initializer(g, sc); - unsafe { - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - } + + llvm::set_global_constant(g, true); + llvm::set_unnamed_address(g, llvm::UnnamedAddr::Global); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); // Cast to default address space if globals are in a different addrspace let g = self.const_pointercast(g, self.type_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5deddb3ed981..070a9b64486f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -19,11 +19,10 @@ use tracing::{debug, instrument, trace}; use crate::common::{AsCCharPtr, CodegenCx}; use crate::errors::SymbolAlreadyDefined; -use crate::llvm::{self, True}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; -use crate::{base, debuginfo}; +use crate::{base, debuginfo, llvm}; pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, @@ -247,7 +246,7 @@ impl<'ll> CodegenCx<'ll, '_> { }; llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); - llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global); gv } @@ -272,9 +271,8 @@ impl<'ll> CodegenCx<'ll, '_> { return gv; } let gv = self.static_addr_of_mut(cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } + llvm::set_global_constant(gv, true); + self.const_globals.borrow_mut().insert(cv, gv); gv } @@ -465,7 +463,7 @@ impl<'ll> CodegenCx<'ll, '_> { // Forward the allocation's mutability (picked by the const interner) to LLVM. if alloc.mutability.is_not() { - llvm::LLVMSetGlobalConstant(g, llvm::True); + llvm::set_global_constant(g, true); } debuginfo::build_global_var_di_node(self, def_id, g); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 8f0948b8183b..3e04dac6cd68 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -75,7 +75,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::set_initializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); - llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); + llvm::set_unnamed_address(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9b4736e50e6c..1a50fb5823b2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1630,7 +1630,7 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( // When full debuginfo is enabled, we want to try and prevent vtables from being // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. - llvm::SetUnnamedAddress(vtable, llvm::UnnamedAddr::No); + llvm::set_unnamed_address(vtable, llvm::UnnamedAddr::No); let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 2419ec1f8885..710032c774b5 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -49,7 +49,7 @@ pub(crate) fn declare_simple_fn<'ll>( }; llvm::SetFunctionCallConv(llfn, callconv); - llvm::SetUnnamedAddress(llfn, unnamed); + llvm::set_unnamed_address(llfn, unnamed); llvm::set_visibility(llfn, visibility); llfn diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 5c34ab2e3040..2af57e22cd5b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1009,7 +1009,7 @@ unsafe extern "C" { ModuleID: *const c_char, C: &Context, ) -> &Module; - pub(crate) fn LLVMCloneModule(M: &Module) -> &Module; + pub(crate) safe fn LLVMCloneModule(M: &Module) -> &Module; /// Data layout. See Module::getDataLayout. pub(crate) fn LLVMGetDataLayoutStr(M: &Module) -> *const c_char; @@ -1179,7 +1179,7 @@ unsafe extern "C" { pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; - pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); + pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes @@ -1718,7 +1718,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; - pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); + pub(crate) safe fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); pub(crate) fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>; diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 3fc83fca352a..154ba4fd6901 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -217,10 +217,8 @@ pub(crate) fn SetUniqueComdat(llmod: &Module, val: &Value) { set_comdat(llmod, val, &name); } -pub(crate) fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) { - unsafe { - LLVMSetUnnamedAddress(global, unnamed); - } +pub(crate) fn set_unnamed_address(global: &Value, unnamed: UnnamedAddr) { + LLVMSetUnnamedAddress(global, unnamed); } pub(crate) fn set_thread_local_mode(global: &Value, mode: ThreadLocalMode) { @@ -260,9 +258,7 @@ pub(crate) fn set_initializer(llglobal: &Value, constant_val: &Value) { } pub(crate) fn set_global_constant(llglobal: &Value, is_constant: bool) { - unsafe { - LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); - } + LLVMSetGlobalConstant(llglobal, if is_constant { ffi::True } else { ffi::False }); } pub(crate) fn get_linkage(llglobal: &Value) -> Linkage { From e574fef728605089da8144960348469896751c3c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:23:05 +0000 Subject: [PATCH 24/64] Shrink some `unsafe` blocks in cg_llvm --- compiler/rustc_codegen_llvm/src/builder.rs | 13 +- compiler/rustc_codegen_llvm/src/consts.rs | 231 +++++++++---------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 4 +- 4 files changed, 127 insertions(+), 129 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9c3b866aa3c6..7304460c4930 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -637,17 +637,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } else if place.layout.is_llvm_immediate() { let mut const_llval = None; let llty = place.layout.llvm_type(self); - unsafe { - if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { - if llvm::LLVMIsGlobalConstant(global) == llvm::True { - if let Some(init) = llvm::LLVMGetInitializer(global) { - if self.val_ty(init) == llty { - const_llval = Some(init); - } + if let Some(global) = llvm::LLVMIsAGlobalVariable(place.val.llval) { + if llvm::LLVMIsGlobalConstant(global) == llvm::True { + if let Some(init) = llvm::LLVMGetInitializer(global) { + if self.val_ty(init) == llty { + const_llval = Some(init); } } } } + let llval = const_llval.unwrap_or_else(|| { let load = self.load(llty, place.val.llval, place.val.align); if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 070a9b64486f..27f6a1197270 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -396,149 +396,148 @@ impl<'ll> CodegenCx<'ll, '_> { } fn codegen_static_item(&mut self, def_id: DefId) { - unsafe { - assert!( - llvm::LLVMGetInitializer( - self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() - ) - .is_none() - ); - let attrs = self.tcx.codegen_fn_attrs(def_id); + assert!( + llvm::LLVMGetInitializer( + self.instances.borrow().get(&Instance::mono(self.tcx, def_id)).unwrap() + ) + .is_none() + ); + let attrs = self.tcx.codegen_fn_attrs(def_id); - let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { - // Error has already been reported - return; - }; - let alloc = alloc.inner(); + let Ok((v, alloc)) = codegen_static_initializer(self, def_id) else { + // Error has already been reported + return; + }; + let alloc = alloc.inner(); - let val_llty = self.val_ty(v); + let val_llty = self.val_ty(v); - let g = self.get_static_inner(def_id, val_llty); - let llty = self.get_type_of_global(g); + let g = self.get_static_inner(def_id, val_llty); + let llty = self.get_type_of_global(g); - let g = if val_llty == llty { - g - } else { - // codegen_static_initializer creates the global value just from the - // `Allocation` data by generating one big struct value that is just - // all the bytes and pointers after each other. This will almost never - // match the type that the static was declared with. Unfortunately - // we can't just LLVMConstBitCast our way out of it because that has very - // specific rules on what can be cast. So instead of adding a new way to - // generate static initializers that match the static's type, we picked - // the easier option and retroactively change the type of the static item itself. - let name = llvm::get_value_name(g); - llvm::set_value_name(g, b""); + let g = if val_llty == llty { + g + } else { + // codegen_static_initializer creates the global value just from the + // `Allocation` data by generating one big struct value that is just + // all the bytes and pointers after each other. This will almost never + // match the type that the static was declared with. Unfortunately + // we can't just LLVMConstBitCast our way out of it because that has very + // specific rules on what can be cast. So instead of adding a new way to + // generate static initializers that match the static's type, we picked + // the easier option and retroactively change the type of the static item itself. + let name = String::from_utf8(llvm::get_value_name(g)) + .expect("we declare our statics with a utf8-valid name"); + llvm::set_value_name(g, b""); - let linkage = llvm::get_linkage(g); - let visibility = llvm::get_visibility(g); + let linkage = llvm::get_linkage(g); + let visibility = llvm::get_visibility(g); - let new_g = llvm::LLVMRustGetOrInsertGlobal( - self.llmod, - name.as_c_char_ptr(), - name.len(), - val_llty, - ); + let new_g = self.declare_global(&name, val_llty); - llvm::set_linkage(new_g, linkage); - llvm::set_visibility(new_g, visibility); + llvm::set_linkage(new_g, linkage); + llvm::set_visibility(new_g, visibility); - // The old global has had its name removed but is returned by - // get_static since it is in the instance cache. Provide an - // alternative lookup that points to the new global so that - // global_asm! can compute the correct mangled symbol name - // for the global. - self.renamed_statics.borrow_mut().insert(def_id, new_g); + // The old global has had its name removed but is returned by + // get_static since it is in the instance cache. Provide an + // alternative lookup that points to the new global so that + // global_asm! can compute the correct mangled symbol name + // for the global. + self.renamed_statics.borrow_mut().insert(def_id, new_g); - // To avoid breaking any invariants, we leave around the old - // global for the moment; we'll replace all references to it - // with the new global later. (See base::codegen_backend.) - self.statics_to_rauw.borrow_mut().push((g, new_g)); - new_g - }; - set_global_alignment(self, g, alloc.align); - llvm::set_initializer(g, v); + // To avoid breaking any invariants, we leave around the old + // global for the moment; we'll replace all references to it + // with the new global later. (See base::codegen_backend.) + self.statics_to_rauw.borrow_mut().push((g, new_g)); + new_g + }; + set_global_alignment(self, g, alloc.align); + llvm::set_initializer(g, v); - self.assume_dso_local(g, true); + self.assume_dso_local(g, true); - // Forward the allocation's mutability (picked by the const interner) to LLVM. - if alloc.mutability.is_not() { - llvm::set_global_constant(g, true); - } + // Forward the allocation's mutability (picked by the const interner) to LLVM. + if alloc.mutability.is_not() { + llvm::set_global_constant(g, true); + } - debuginfo::build_global_var_di_node(self, def_id, g); + debuginfo::build_global_var_di_node(self, def_id, g); - if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { - llvm::set_thread_local_mode(g, self.tls_model); - } + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + llvm::set_thread_local_mode(g, self.tls_model); + } - // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. The exception to this - // is the `.init_array` section which are treated specially by the wasm linker. - if self.tcx.sess.target.is_like_wasm - && attrs - .link_section - .map(|link_section| !link_section.as_str().starts_with(".init_array")) - .unwrap_or(true) - { - if let Some(section) = attrs.link_section { - let section = llvm::LLVMMDStringInContext2( + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { + if let Some(section) = attrs.link_section { + let section = unsafe { + llvm::LLVMMDStringInContext2( self.llcx, section.as_str().as_c_char_ptr(), section.as_str().len(), - ); - assert!(alloc.provenance().ptrs().is_empty()); + ) + }; + assert!(alloc.provenance().ptrs().is_empty()); - // The `inspect` method is okay here because we checked for provenance, and - // because we are doing this access to inspect the final interpreter state (not - // as part of the interpreter execution). - let bytes = - alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); - let data = [section, alloc]; - let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = self.get_metadata_value(meta); + // The `inspect` method is okay here because we checked for provenance, and + // because we are doing this access to inspect the final interpreter state (not + // as part of the interpreter execution). + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); + let alloc = unsafe { + llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()) + }; + let data = [section, alloc]; + let meta = + unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; + let val = self.get_metadata_value(meta); + unsafe { llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), val, - ); - } - } else { - base::set_link_section(g, attrs); + ) + }; } + } else { + base::set_link_section(g, attrs); + } - base::set_variable_sanitizer_attrs(g, attrs); + base::set_variable_sanitizer_attrs(g, attrs); - if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + if attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); - // The semantics of #[used] in Rust only require the symbol to make it into the - // object file. It is explicitly allowed for the linker to strip the symbol if it - // is dead, which means we are allowed to use `llvm.compiler.used` instead of - // `llvm.used` here. - // - // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique - // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs - // in the handling of `.init_array` (the static constructor list) in versions of - // the gold linker (prior to the one released with binutils 2.36). - // - // That said, we only ever emit these when `#[used(compiler)]` is explicitly - // requested. This is to avoid similar breakage on other targets, in particular - // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` - // is emitted rather than `llvm.used`. However, that check happens when assigning - // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to - // take care of it here. - self.add_compiler_used_global(g); - } - if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { - // `USED` and `USED_LINKER` can't be used together. - assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); + // The semantics of #[used] in Rust only require the symbol to make it into the + // object file. It is explicitly allowed for the linker to strip the symbol if it + // is dead, which means we are allowed to use `llvm.compiler.used` instead of + // `llvm.used` here. + // + // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique + // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs + // in the handling of `.init_array` (the static constructor list) in versions of + // the gold linker (prior to the one released with binutils 2.36). + // + // That said, we only ever emit these when `#[used(compiler)]` is explicitly + // requested. This is to avoid similar breakage on other targets, in particular + // MachO targets have *their* static constructor lists broken if `llvm.compiler.used` + // is emitted rather than `llvm.used`. However, that check happens when assigning + // the `CodegenFnAttrFlags` in the `codegen_fn_attrs` query, so we don't need to + // take care of it here. + self.add_compiler_used_global(g); + } + if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)); - self.add_used_global(g); - } + self.add_used_global(g); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2af57e22cd5b..0b1e632cbc42 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1168,17 +1168,17 @@ unsafe extern "C" { pub(crate) fn LLVMGlobalGetValueType(Global: &Value) -> &Type; // Operations on global variables - pub(crate) fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMAddGlobal<'a>(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value; pub(crate) fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>; pub(crate) fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>; pub(crate) fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMDeleteGlobal(GlobalVar: &Value); - pub(crate) fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; + pub(crate) safe fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; pub(crate) fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value); - pub(crate) fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); - pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; + pub(crate) safe fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191bf..8f70270f203e 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -131,8 +131,8 @@ impl CodegenCx<'_, '_> { } // Thread-local variables generally don't support copy relocations. - let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) } - .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True); + let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) + .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); if is_thread_local_var { return false; } From b9baf63f99bbdf69571e26fca907af032c416591 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:31:58 +0000 Subject: [PATCH 25/64] Merge `typeid_metadata` and `create_metadata` --- compiler/rustc_codegen_llvm/src/builder.rs | 2 +- .../rustc_codegen_llvm/src/builder/autodiff.rs | 16 ++++++++-------- compiler/rustc_codegen_llvm/src/context.rs | 7 ++++--- compiler/rustc_codegen_llvm/src/type_.rs | 10 ++++------ 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 7304460c4930..4c5bc8430cc7 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1720,7 +1720,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.cx.create_metadata(typeid); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 5afb9a60d424..9383903fd022 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); + let enzyme_const = cx.create_metadata("enzyme_const".to_string()); + let enzyme_out = cx.create_metadata("enzyme_out".to_string()); + let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()); + let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()); + let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()); + let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); + let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); + let enzyme_width = cx.create_metadata("enzyme_width".to_string()); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 90582e23b04c..5616c4d4e457 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -473,6 +473,7 @@ pub(crate) unsafe fn create_module<'ll>( #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); + let name_metadata = unsafe { llvm::LLVMMDStringInContext2( llcx, @@ -698,10 +699,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { - Some(unsafe { + pub(crate) fn create_metadata(&self, name: String) -> &'ll Metadata { + unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) - }) + } } pub(crate) fn get_functions(&self) -> Vec<&'ll Value> { diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ee472e75ed41..5b19ca91e4d1 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use std::hash::{Hash, Hasher}; use std::{fmt, ptr}; -use libc::{c_char, c_uint}; +use libc::c_uint; use rustc_abi::{AddressSpace, Align, Integer, Reg, Size}; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; @@ -299,7 +299,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn add_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMRustGlobalAddMetadata( @@ -311,7 +311,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn set_type_metadata(&self, function: &'ll Value, typeid: String) { - let typeid_metadata = self.typeid_metadata(typeid).unwrap(); + let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; llvm::LLVMGlobalSetMetadata( @@ -323,9 +323,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { - Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, typeid.as_ptr() as *const c_char, typeid.len()) - }) + Some(self.create_metadata(typeid)) } fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) { From 56d22cd29ff6d3ea1fa8972462ad94792960b1ef Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:36:19 +0000 Subject: [PATCH 26/64] Use context methods instead of directly calling FFI --- compiler/rustc_codegen_llvm/src/builder.rs | 4 +--- compiler/rustc_codegen_llvm/src/consts.rs | 8 +------- compiler/rustc_codegen_llvm/src/context.rs | 14 +++++--------- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 8 ++------ 4 files changed, 9 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4c5bc8430cc7..3c64cb79d5e1 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -303,9 +303,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } let id_str = "branch_weights"; - let id = unsafe { - llvm::LLVMMDStringInContext2(self.cx.llcx, id_str.as_ptr().cast(), id_str.len()) - }; + let id = self.cx.create_metadata(id_str.into()); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 27f6a1197270..40e686b253cf 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -477,13 +477,7 @@ impl<'ll> CodegenCx<'ll, '_> { .unwrap_or(true) { if let Some(section) = attrs.link_section { - let section = unsafe { - llvm::LLVMMDStringInContext2( - self.llcx, - section.as_str().as_c_char_ptr(), - section.as_str().len(), - ) - }; + let section = self.create_metadata(section.as_str().into()); assert!(alloc.provenance().ptrs().is_empty()); // The `inspect` method is okay here because we checked for provenance, and diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 5616c4d4e457..51ba3fb8089b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,7 +34,6 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; use crate::llvm::Metadata; use crate::type_::Type; @@ -169,6 +168,8 @@ pub(crate) unsafe fn create_module<'ll>( let mod_name = SmallCStr::new(mod_name); let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; + let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size()); + let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); @@ -474,18 +475,13 @@ pub(crate) unsafe fn create_module<'ll>( let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = unsafe { - llvm::LLVMMDStringInContext2( - llcx, - rustc_producer.as_c_char_ptr(), - rustc_producer.as_bytes().len(), - ) - }; + let name_metadata = cx.create_metadata(rustc_producer); + unsafe { llvm::LLVMAddNamedMetadataOperand( llmod, c"llvm.ident".as_ptr(), - &llvm::LLVMMetadataAsValue(llcx, llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), + &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)), ); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1a50fb5823b2..3fdf4e19d588 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use std::{iter, ptr}; -use libc::{c_char, c_longlong, c_uint}; +use libc::{c_longlong, c_uint}; use rustc_abi::{Align, Size}; use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo}; use rustc_codegen_ssa::traits::*; @@ -1582,13 +1582,9 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); + let typeid = cx.create_metadata(trait_ref_typeid); unsafe { - let typeid = llvm::LLVMMDStringInContext2( - cx.llcx, - trait_ref_typeid.as_ptr() as *const c_char, - trait_ref_typeid.as_bytes().len(), - ); let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; llvm::LLVMRustGlobalAddMetadata( vtable, From 7f95f042677f86df55da58cdebe9ce31a1e928a8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 09:48:46 +0000 Subject: [PATCH 27/64] Eliminate all direct uses of LLVMMDStringInContext2 --- compiler/rustc_codegen_llvm/src/builder.rs | 5 ++--- .../rustc_codegen_llvm/src/builder/autodiff.rs | 16 ++++++++-------- compiler/rustc_codegen_llvm/src/consts.rs | 8 +++----- compiler/rustc_codegen_llvm/src/context.rs | 4 ++-- .../rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 4 ++-- compiler/rustc_codegen_llvm/src/type_.rs | 6 +++--- compiler/rustc_codegen_ssa/src/meth.rs | 3 ++- compiler/rustc_codegen_ssa/src/traits/type_.rs | 6 +++--- 9 files changed, 26 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 3c64cb79d5e1..514923ad6f37 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -302,8 +302,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } - let id_str = "branch_weights"; - let id = self.cx.create_metadata(id_str.into()); + let id = self.cx.create_metadata(b"branch_weights"); // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used. // This function handles switch instructions with more than 2 targets and it needs to @@ -1718,7 +1717,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } else { cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - let typeid_metadata = self.cx.create_metadata(typeid); + let typeid_metadata = self.cx.create_metadata(typeid.as_bytes()); let dbg_loc = self.get_dbg_loc(); // Test whether the function pointer is associated with the type identifier using the diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 9383903fd022..dff684728473 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -76,12 +76,12 @@ fn match_args_from_caller_to_enzyme<'ll>( outer_pos = 1; } - let enzyme_const = cx.create_metadata("enzyme_const".to_string()); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()); + let enzyme_const = cx.create_metadata(b"enzyme_const"); + let enzyme_out = cx.create_metadata(b"enzyme_out"); + let enzyme_dup = cx.create_metadata(b"enzyme_dup"); + let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); + let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); + let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -378,12 +378,12 @@ fn generate_enzyme_call<'ll>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()); + let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()); + let enzyme_width = cx.create_metadata(b"enzyme_width"); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 40e686b253cf..0b96b63bc857 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; -use crate::common::{AsCCharPtr, CodegenCx}; +use crate::common::CodegenCx; use crate::errors::SymbolAlreadyDefined; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -477,16 +477,14 @@ impl<'ll> CodegenCx<'ll, '_> { .unwrap_or(true) { if let Some(section) = attrs.link_section { - let section = self.create_metadata(section.as_str().into()); + let section = self.create_metadata(section.as_str().as_bytes()); assert!(alloc.provenance().ptrs().is_empty()); // The `inspect` method is okay here because we checked for provenance, and // because we are doing this access to inspect the final interpreter state (not // as part of the interpreter execution). let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()); - let alloc = unsafe { - llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()) - }; + let alloc = self.create_metadata(bytes); let data = [section, alloc]; let meta = unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) }; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 51ba3fb8089b..6a23becaa96f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -475,7 +475,7 @@ pub(crate) unsafe fn create_module<'ll>( let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = cx.create_metadata(rustc_producer); + let name_metadata = cx.create_metadata(rustc_producer.as_bytes()); unsafe { llvm::LLVMAddNamedMetadataOperand( @@ -695,7 +695,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } - pub(crate) fn create_metadata(&self, name: String) -> &'ll Metadata { + pub(crate) fn create_metadata(&self, name: &[u8]) -> &'ll Metadata { unsafe { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 3fdf4e19d588..0e9dbfba658d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1582,7 +1582,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( }; let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref); - let typeid = cx.create_metadata(trait_ref_typeid); + let typeid = cx.create_metadata(trait_ref_typeid.as_bytes()); unsafe { let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid]; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 710032c774b5..eb75716d768b 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -176,7 +176,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { { let typeid = cfi::typeid_for_instance(self.tcx, instance, options); if typeids.insert(typeid.clone()) { - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } else { @@ -189,7 +189,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { .map(cfi::TypeIdOptions::from_iter) { let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); - self.add_type_metadata(llfn, typeid); + self.add_type_metadata(llfn, typeid.as_bytes()); } } } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 5b19ca91e4d1..893655031388 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -298,7 +298,7 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn add_type_metadata(&self, function: &'ll Value, typeid: String) { + fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; @@ -310,7 +310,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn set_type_metadata(&self, function: &'ll Value, typeid: String) { + fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) { let typeid_metadata = self.create_metadata(typeid); unsafe { let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata]; @@ -322,7 +322,7 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn typeid_metadata(&self, typeid: String) -> Option<&'ll Metadata> { + fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> { Some(self.create_metadata(typeid)) } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 2aa5c3c27ea5..34ad35a729b9 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -139,7 +139,8 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( && bx.cx().sess().lto() == Lto::Fat { if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { - let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); + let typeid = + bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref).as_bytes()).unwrap(); let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); return func; } else if nonnull { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index dcd9e25b2c95..32c24965e1bf 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -154,9 +154,9 @@ pub trait LayoutTypeCodegenMethods<'tcx>: BackendTypes { // For backends that support CFI using type membership (i.e., testing whether a given pointer is // associated with a type identifier). pub trait TypeMembershipCodegenMethods<'tcx>: BackendTypes { - fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {} - fn typeid_metadata(&self, _typeid: String) -> Option { + fn add_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn set_type_metadata(&self, _function: Self::Function, _typeid: &[u8]) {} + fn typeid_metadata(&self, _typeid: &[u8]) -> Option { None } fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {} From eef08a3f440967d72bf0e8ef8f3c7571abb64738 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 10 Jul 2025 14:55:07 +0000 Subject: [PATCH 28/64] Give all bytes of TypeId provenance --- .../src/interpret/intrinsics.rs | 70 ++++++++++--------- tests/ui/consts/const_transmute_type_id3.rs | 5 +- .../ui/consts/const_transmute_type_id3.stderr | 4 +- tests/ui/consts/const_transmute_type_id5.rs | 21 ++++++ .../ui/consts/const_transmute_type_id5.stderr | 15 ++++ 5 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 tests/ui/consts/const_transmute_type_id5.rs create mode 100644 tests/ui/consts/const_transmute_type_id5.stderr diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 1eba1f2f03c9..22d29eda913a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -44,17 +44,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; self.copy_op_allow_transmute(&op, dest)?; - // Give the first pointer-size bytes provenance that knows about the type id. + // Give the each pointer-sized chunk provenance that knows about the type id. // Here we rely on `TypeId` being a newtype around an array of pointers, so we - // first project to its only field and then the first array element. + // first project to its only field and then the array elements. let alloc_id = tcx.reserve_and_set_type_id_alloc(ty); let first = self.project_field(dest, FieldIdx::ZERO)?; - let first = self.project_index(&first, 0)?; - let offset = self.read_scalar(&first)?.to_target_usize(&tcx)?; - let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset)); - let ptr = self.global_root_pointer(ptr)?; - let val = Scalar::from_pointer(ptr, &tcx); - self.write_scalar(val, &first) + let mut elem_iter = self.project_array_fields(&first)?; + while let Some((_, elem)) = elem_iter.next(self)? { + // Decorate this part of the hash with provenance; leave the integer part unchanged. + let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?; + let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(hash_fragment)); + let ptr = self.global_root_pointer(ptr)?; + let val = Scalar::from_pointer(ptr, &tcx); + self.write_scalar(val, &elem)?; + } + interp_ok(()) } /// Returns `true` if emulation happened. @@ -101,34 +105,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let mut a_fields = self.project_array_fields(&a_fields)?; let mut b_fields = self.project_array_fields(&b_fields)?; - let (_idx, a) = a_fields - .next(self)? - .expect("we know the layout of TypeId has at least 2 array elements"); - let a = self.deref_pointer(&a)?; - let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; + let mut provenance_a = None; + let mut provenance_b = None; + let mut provenance_matches = true; - let (_idx, b) = b_fields - .next(self)? - .expect("we know the layout of TypeId has at least 2 array elements"); - let b = self.deref_pointer(&b)?; - let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; - - let provenance_matches = a == b; - - let mut eq_id = offset_a == offset_b; - - while let Some((_, a)) = a_fields.next(self)? { + while let Some((i, a)) = a_fields.next(self)? { let (_, b) = b_fields.next(self)?.unwrap(); - let a = self.read_target_usize(&a)?; - let b = self.read_target_usize(&b)?; - eq_id &= a == b; - } + let a = self.deref_pointer(&a)?; + let (a, offset_a) = self.get_ptr_type_id(a.ptr())?; - if !eq_id && provenance_matches { - throw_ub_format!( - "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents" - ) + let b = self.deref_pointer(&b)?; + let (b, offset_b) = self.get_ptr_type_id(b.ptr())?; + + if *provenance_a.get_or_insert(a) != a { + throw_ub_format!( + "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" + ) + } + if *provenance_b.get_or_insert(b) != b { + throw_ub_format!( + "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" + ) + } + provenance_matches &= a == b; + + if offset_a != offset_b && provenance_matches { + throw_ub_format!( + "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents" + ) + } } self.write_scalar(Scalar::from_bool(provenance_matches), dest)?; diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs index ed5ff769701f..f1bb8cddf774 100644 --- a/tests/ui/consts/const_transmute_type_id3.rs +++ b/tests/ui/consts/const_transmute_type_id3.rs @@ -1,3 +1,6 @@ +//! Test that all bytes of a TypeId must have the +//! TypeId marker provenance. + #![feature(const_type_id, const_trait_impl, const_cmp)] use std::any::TypeId; @@ -10,7 +13,7 @@ const _: () = { std::ptr::write(ptr.offset(1), 999); } assert!(a == b); - //~^ ERROR: one of the TypeId arguments is invalid, the hash does not match the type it represents + //~^ ERROR: pointer must point to some allocation }; fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr index 8cfdcfebaa4c..e731f496652e 100644 --- a/tests/ui/consts/const_transmute_type_id3.stderr +++ b/tests/ui/consts/const_transmute_type_id3.stderr @@ -1,5 +1,5 @@ -error[E0080]: type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents - --> $DIR/const_transmute_type_id3.rs:12:13 +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x3e7[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/const_transmute_type_id3.rs:15:13 | LL | assert!(a == b); | ^^^^^^ evaluation of `_` failed inside this call diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs new file mode 100644 index 000000000000..0a9ba01e0dd7 --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id5.rs @@ -0,0 +1,21 @@ +//! Test that we require an equal TypeId to have the same integer +//! part, even if the provenance matches. + +#![feature(const_type_id, const_trait_impl, const_cmp)] + +use std::any::TypeId; + +const _: () = { + let a = TypeId::of::<()>(); + let mut b = TypeId::of::<()>(); + unsafe { + let ptr = &mut b as *mut TypeId as *mut *const (); + // Copy the ptr at index 0 to index 1 + let val = std::ptr::read(ptr); + std::ptr::write(ptr.offset(1), val); + } + assert!(a == b); + //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents +}; + +fn main() {} diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr new file mode 100644 index 000000000000..59823fcc1c9f --- /dev/null +++ b/tests/ui/consts/const_transmute_type_id5.stderr @@ -0,0 +1,15 @@ +error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents + --> $DIR/const_transmute_type_id5.rs:17:13 + | +LL | assert!(a == b); + | ^^^^^^ evaluation of `_` failed inside this call + | +note: inside `::eq` + --> $SRC_DIR/core/src/any.rs:LL:COL +note: inside `::eq::compiletime` + --> $SRC_DIR/core/src/any.rs:LL:COL + = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From 9fd3886838afd28ee3834d0e7162fd6ab5adc944 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 13 Jul 2025 22:53:57 +0000 Subject: [PATCH 29/64] Add experimental backtrace-trace-only std feature --- library/std/Cargo.toml | 3 + library/std/src/sys/backtrace.rs | 98 +++++++++++++++++--------------- library/sysroot/Cargo.toml | 1 + 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 62ece4b69619..86d23df52381 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -92,6 +92,9 @@ backtrace = [ 'object/rustc-dep-of-std', 'miniz_oxide/rustc-dep-of-std', ] +# Disable symbolization in backtraces. For use with -Zbuild-std. +# FIXME: Ideally this should be an additive backtrace-symbolization feature +backtrace-trace-only = [] panic-unwind = ["dep:panic_unwind"] compiler-builtins-c = ["alloc/compiler-builtins-c"] diff --git a/library/std/src/sys/backtrace.rs b/library/std/src/sys/backtrace.rs index efa6a896dad8..272d0fa4d1a1 100644 --- a/library/std/src/sys/backtrace.rs +++ b/library/std/src/sys/backtrace.rs @@ -68,61 +68,67 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: return false; } - let mut hit = false; - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - hit = true; + if cfg!(feature = "backtrace-trace-only") { + const HEX_WIDTH: usize = 2 + 2 * size_of::(); + let frame_ip = frame.ip(); + res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); + } else { + let mut hit = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; - // `__rust_end_short_backtrace` means we are done hiding symbols - // for now. Print until we see `__rust_begin_short_backtrace`. - if print_fmt == PrintFmt::Short { - if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { - if sym.contains("__rust_end_short_backtrace") { - print = true; - return; - } - if print && sym.contains("__rust_begin_short_backtrace") { - print = false; - return; - } - if !print { - omitted_count += 1; + // `__rust_end_short_backtrace` means we are done hiding symbols + // for now. Print until we see `__rust_begin_short_backtrace`. + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_end_short_backtrace") { + print = true; + return; + } + if print && sym.contains("__rust_begin_short_backtrace") { + print = false; + return; + } + if !print { + omitted_count += 1; + } } } - } - if print { - if omitted_count > 0 { - debug_assert!(print_fmt == PrintFmt::Short); - // only print the message between the middle of frames - if !first_omit { - let _ = writeln!( - bt_fmt.formatter(), - " [... omitted {} frame{} ...]", - omitted_count, - if omitted_count > 1 { "s" } else { "" } - ); + if print { + if omitted_count > 0 { + debug_assert!(print_fmt == PrintFmt::Short); + // only print the message between the middle of frames + if !first_omit { + let _ = writeln!( + bt_fmt.formatter(), + " [... omitted {} frame{} ...]", + omitted_count, + if omitted_count > 1 { "s" } else { "" } + ); + } + first_omit = false; + omitted_count = 0; } - first_omit = false; - omitted_count = 0; + res = bt_fmt.frame().symbol(frame, symbol); } - res = bt_fmt.frame().symbol(frame, symbol); + }); + #[cfg(target_os = "nto")] + if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { + if !hit && print { + use crate::backtrace_rs::SymbolName; + res = bt_fmt.frame().print_raw( + frame.ip(), + Some(SymbolName::new("__my_thread_exit".as_bytes())), + None, + None, + ); + } + return false; } - }); - #[cfg(target_os = "nto")] - if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && print { - use crate::backtrace_rs::SymbolName; - res = bt_fmt.frame().print_raw( - frame.ip(), - Some(SymbolName::new("__my_thread_exit".as_bytes())), - None, - None, - ); + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } - return false; - } - if !hit && print { - res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } idx += 1; diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 290c2eeed44c..032f5272a9cd 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -20,6 +20,7 @@ test = { path = "../test", public = true } [features] default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] backtrace = ["std/backtrace"] +backtrace-trace-only = ["std/backtrace-trace-only"] compiler-builtins-c = ["std/compiler-builtins-c"] compiler-builtins-mem = ["std/compiler-builtins-mem"] compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"] From 000e67aafb7ae8c755387a073f34662c4f6fc335 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 9 Jul 2025 07:25:12 +0000 Subject: [PATCH 30/64] Preserve constness in trait objects up to hir ty lowering --- .../src/hir_ty_lowering/dyn_compatibility.rs | 2 +- .../const-trait-bounds-trait-objects.rs | 2 ++ .../const-trait-bounds-trait-objects.stderr | 26 +++++++++++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index cb106962be18..364ad38556be 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -49,7 +49,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } = self.lower_poly_trait_ref( &trait_bound.trait_ref, trait_bound.span, - hir::BoundConstness::Never, + trait_bound.modifiers.constness, hir::BoundPolarity::Positive, dummy_self, &mut user_written_bounds, diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs index ece87529c3e3..1d1da9b0e3df 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs @@ -14,5 +14,7 @@ fn main() { trait NonConst {} const fn handle(_: &dyn const NonConst) {} //~^ ERROR const trait bounds are not allowed in trait object types +//~| ERROR `const` can only be applied to `#[const_trait]` traits const fn take(_: &dyn [const] NonConst) {} //~^ ERROR `[const]` is not allowed here +//~| ERROR `[const]` can only be applied to `#[const_trait]` traits diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr index 090555c63779..06e0493024c1 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr @@ -19,12 +19,34 @@ LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:17:23 + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ | = note: trait objects cannot have `[const]` trait bounds -error: aborting due to 4 previous errors +error: `const` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:15:25 + | +LL | const fn handle(_: &dyn const NonConst) {} + | ^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: `[const]` can only be applied to `#[const_trait]` traits + --> $DIR/const-trait-bounds-trait-objects.rs:18:23 + | +LL | const fn take(_: &dyn [const] NonConst) {} + | ^^^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ + +error: aborting due to 6 previous errors From 1b8d65ed29e17e24d0acecf1986ab320c5747a85 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Mon, 14 Jul 2025 18:10:41 +0200 Subject: [PATCH 31/64] rustc_type_ir/walk: move docstring to `TypeWalker` itself having it on the impl block is a bit weird imo --- compiler/rustc_type_ir/src/walk.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs index 737550eb73e9..9912fad1756e 100644 --- a/compiler/rustc_type_ir/src/walk.rs +++ b/compiler/rustc_type_ir/src/walk.rs @@ -12,12 +12,6 @@ use crate::{self as ty, Interner}; // avoid heap allocations. type TypeWalkerStack = SmallVec<[::GenericArg; 8]>; -pub struct TypeWalker { - stack: TypeWalkerStack, - last_subtree: usize, - pub visited: SsoHashSet, -} - /// An iterator for walking the type tree. /// /// It's very easy to produce a deeply @@ -26,6 +20,12 @@ pub struct TypeWalker { /// in this situation walker only visits each type once. /// It maintains a set of visited types and /// skips any types that are already there. +pub struct TypeWalker { + stack: TypeWalkerStack, + last_subtree: usize, + pub visited: SsoHashSet, +} + impl TypeWalker { pub fn new(root: I::GenericArg) -> Self { Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } From ae1b1b4f8a9a1cd012cd7db944bbfa2adae703cb Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Tue, 10 Jun 2025 18:36:22 +0200 Subject: [PATCH 32/64] tests: Fix duplicated-path-in-error fail with musl musl's dlopen returns a different error than glibc, which contains the name of the file. This would cause the test to fail, since the filename would appear twice in the output (once in the error from rustc, once in the error message from musl). Split the expected test outputs for the different libc implementations. Signed-off-by: Jens Reidel --- src/tools/compiletest/src/directives.rs | 1 + ...in-error.stderr => duplicated-path-in-error.gnu.stderr} | 0 tests/ui/codegen/duplicated-path-in-error.musl.stderr | 2 ++ tests/ui/codegen/duplicated-path-in-error.rs | 7 +++++++ 4 files changed, 10 insertions(+) rename tests/ui/codegen/{duplicated-path-in-error.stderr => duplicated-path-in-error.gnu.stderr} (100%) create mode 100644 tests/ui/codegen/duplicated-path-in-error.musl.stderr diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 215793fe947f..e31f8f43e1b9 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -973,6 +973,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-mips64", "only-msp430", "only-msvc", + "only-musl", "only-nightly", "only-nvptx64", "only-powerpc", diff --git a/tests/ui/codegen/duplicated-path-in-error.stderr b/tests/ui/codegen/duplicated-path-in-error.gnu.stderr similarity index 100% rename from tests/ui/codegen/duplicated-path-in-error.stderr rename to tests/ui/codegen/duplicated-path-in-error.gnu.stderr diff --git a/tests/ui/codegen/duplicated-path-in-error.musl.stderr b/tests/ui/codegen/duplicated-path-in-error.musl.stderr new file mode 100644 index 000000000000..2892ebffdde6 --- /dev/null +++ b/tests/ui/codegen/duplicated-path-in-error.musl.stderr @@ -0,0 +1,2 @@ +error: couldn't load codegen backend /non-existing-one.so: Error loading shared library /non-existing-one.so: No such file or directory + diff --git a/tests/ui/codegen/duplicated-path-in-error.rs b/tests/ui/codegen/duplicated-path-in-error.rs index a446395de208..fed93828ee2a 100644 --- a/tests/ui/codegen/duplicated-path-in-error.rs +++ b/tests/ui/codegen/duplicated-path-in-error.rs @@ -1,8 +1,15 @@ +//@ revisions: musl gnu //@ only-linux +//@ ignore-cross-compile because this relies on host libc behaviour //@ compile-flags: -Zcodegen-backend=/non-existing-one.so +//@[gnu] only-gnu +//@[musl] only-musl // This test ensures that the error of the "not found dylib" doesn't duplicate // the path of the dylib. +// +// glibc and musl have different dlopen error messages, so the expected error +// message differs between the two. fn main() {} From 904273c58e474877786679f89a6a7e15b75acfb1 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:31:37 +0800 Subject: [PATCH 33/64] Register change tracker warning for removal of `./x suggest` --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 1f6ed8129da8..d888a7863bcb 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -476,4 +476,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Option `tool.TOOL_NAME.features` now works on any subcommand, not just `build`.", }, + ChangeInfo { + change_id: 143630, + severity: ChangeSeverity::Warning, + summary: "The current `./x suggest` implementation has been removed due to it being quite broken and a lack of maintenance bandwidth, with no prejudice against re-implementing it in a more maintainable form.", + }, ]; From 91d064b44286d87723fc8ef2ae9d8e3d047d12f2 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:52:00 +0800 Subject: [PATCH 34/64] Remove current implementation of `./x suggest` This is quite a bit of implementation complexity, yet it is quite broken, and we don't have the maintenance bandwidth to address. Remove the current implementation if only to reduce bootstrap's implementation complexity; the `suggest` flow comes with its own set of hacks. --- Cargo.lock | 8 -- Cargo.toml | 1 - src/bootstrap/src/core/build_steps/mod.rs | 1 - src/bootstrap/src/core/build_steps/suggest.rs | 68 ------------- src/bootstrap/src/core/build_steps/test.rs | 9 +- src/bootstrap/src/core/build_steps/tool.rs | 1 - src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 6 +- src/bootstrap/src/core/config/config.rs | 2 - src/bootstrap/src/core/config/flags.rs | 8 -- src/bootstrap/src/core/sanity.rs | 1 - src/bootstrap/src/lib.rs | 11 +-- src/bootstrap/src/utils/cc_detect.rs | 1 - src/bootstrap/src/utils/metrics.rs | 2 +- src/tools/suggest-tests/Cargo.toml | 8 -- .../suggest-tests/src/dynamic_suggestions.rs | 32 ------- src/tools/suggest-tests/src/lib.rs | 96 ------------------- src/tools/suggest-tests/src/main.rs | 40 -------- .../suggest-tests/src/static_suggestions.rs | 40 -------- src/tools/suggest-tests/src/tests.rs | 21 ---- 20 files changed, 10 insertions(+), 348 deletions(-) delete mode 100644 src/bootstrap/src/core/build_steps/suggest.rs delete mode 100644 src/tools/suggest-tests/Cargo.toml delete mode 100644 src/tools/suggest-tests/src/dynamic_suggestions.rs delete mode 100644 src/tools/suggest-tests/src/lib.rs delete mode 100644 src/tools/suggest-tests/src/main.rs delete mode 100644 src/tools/suggest-tests/src/static_suggestions.rs delete mode 100644 src/tools/suggest-tests/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index a6c36b4bdfa7..ff2b21c64b0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5188,14 +5188,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "suggest-tests" -version = "0.1.0" -dependencies = [ - "build_helper", - "glob", -] - [[package]] name = "syn" version = "1.0.109" diff --git a/Cargo.toml b/Cargo.toml index 6d3425f4115a..67c7a9d67edc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,6 @@ members = [ "src/tools/rustdoc-gui-test", "src/tools/rustdoc-themes", "src/tools/rustfmt", - "src/tools/suggest-tests", "src/tools/test-float-parse", "src/tools/tidy", "src/tools/tier-check", diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index fcb6abea4347..c2ad9a4df597 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -11,7 +11,6 @@ pub(crate) mod llvm; pub(crate) mod perf; pub(crate) mod run; pub(crate) mod setup; -pub(crate) mod suggest; pub(crate) mod synthetic_targets; pub(crate) mod test; pub(crate) mod tool; diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs deleted file mode 100644 index fd4918961adb..000000000000 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Attempt to magically identify good tests to run - -use std::path::PathBuf; -use std::str::FromStr; - -use clap::Parser; - -use crate::core::build_steps::tool::Tool; -use crate::core::builder::Builder; - -/// Suggests a list of possible `x.py` commands to run based on modified files in branch. -pub fn suggest(builder: &Builder<'_>, run: bool) { - let git_config = builder.config.git_config(); - let suggestions = builder - .tool_cmd(Tool::SuggestTests) - .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch) - .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email) - .run_capture_stdout(builder) - .stdout(); - - let suggestions = suggestions - .lines() - .map(|line| { - let mut sections = line.split_ascii_whitespace(); - - // this code expects one suggestion per line in the following format: - // {some number of flags} [optional stage number] - let cmd = sections.next().unwrap(); - let stage = sections.next_back().and_then(|s| str::parse(s).ok()); - let paths: Vec = sections.map(|p| PathBuf::from_str(p).unwrap()).collect(); - - (cmd, stage, paths) - }) - .collect::>(); - - if !suggestions.is_empty() { - println!("==== SUGGESTIONS ===="); - for sug in &suggestions { - print!("x {} ", sug.0); - if let Some(stage) = sug.1 { - print!("--stage {stage} "); - } - - for path in &sug.2 { - print!("{} ", path.display()); - } - println!(); - } - println!("====================="); - } else { - println!("No suggestions found!"); - return; - } - - if run { - for sug in suggestions { - let mut build: crate::Build = builder.build.clone(); - build.config.paths = sug.2; - build.config.cmd = crate::core::config::flags::Flags::parse_from(["x.py", sug.0]).cmd; - if let Some(stage) = sug.1 { - build.config.stage = stage; - } - build.build(); - } - } else { - println!("HELP: consider using the `--run` flag to automatically run suggested tests"); - } -} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 757eac1475c1..9e7ea5c115f1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -47,12 +47,11 @@ impl Step for CrateBootstrap { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - // This step is responsible for several different tool paths. By default - // it will test all of them, but requesting specific tools on the - // command-line (e.g. `./x test suggest-tests`) will test only the - // specified tools. + // This step is responsible for several different tool paths. + // + // By default, it will test all of them, but requesting specific tools on the command-line + // (e.g. `./x test src/tools/coverage-dump`) will test only the specified tools. run.path("src/tools/jsondoclint") - .path("src/tools/suggest-tests") .path("src/tools/replace-version-placeholder") .path("src/tools/coverage-dump") // We want `./x test tidy` to _run_ the tidy tool, not its tests. diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 814a44b9a13b..1c994b0ccfc8 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -517,7 +517,6 @@ bootstrap_tool!( ReplaceVersionPlaceholder, "src/tools/replace-version-placeholder", "replace-version-placeholder"; CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; - SuggestTests, "src/tools/suggest-tests", "suggest-tests"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index d5a290d804c5..a3b471ca56eb 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -113,7 +113,7 @@ impl Cargo { match cmd_kind { // No need to configure the target linker for these command types. - Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {} + Kind::Clean | Kind::Check | Kind::Format | Kind::Setup => {} _ => { cargo.configure_linker(builder, mode); } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 7115c5a1cbe7..1b75d00b30e4 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -845,7 +845,6 @@ pub enum Kind { #[value(alias = "r")] Run, Setup, - Suggest, Vendor, Perf, } @@ -869,7 +868,6 @@ impl Kind { Kind::Install => "install", Kind::Run => "run", Kind::Setup => "setup", - Kind::Suggest => "suggest", Kind::Vendor => "vendor", Kind::Perf => "perf", } @@ -881,7 +879,6 @@ impl Kind { Kind::Bench => "Benchmarking", Kind::Doc => "Documenting", Kind::Run => "Running", - Kind::Suggest => "Suggesting", Kind::Clippy => "Linting", Kind::Perf => "Profiling & benchmarking", _ => { @@ -1201,7 +1198,7 @@ impl<'a> Builder<'a> { Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), Kind::Vendor => describe!(vendor::Vendor), // special-cased in Build::build() - Kind::Format | Kind::Suggest | Kind::Perf => vec![], + Kind::Format | Kind::Perf => vec![], Kind::MiriTest | Kind::MiriSetup => unreachable!(), } } @@ -1269,7 +1266,6 @@ impl<'a> Builder<'a> { Subcommand::Run { .. } => (Kind::Run, &paths[..]), Subcommand::Clean { .. } => (Kind::Clean, &paths[..]), Subcommand::Format { .. } => (Kind::Format, &[][..]), - Subcommand::Suggest { .. } => (Kind::Suggest, &[][..]), Subcommand::Setup { profile: ref path } => ( Kind::Setup, path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)), diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0039d44785c3..28958b60fc32 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1050,7 +1050,6 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } | Subcommand::Vendor { .. } => flags_stage.unwrap_or(0), }; @@ -1098,7 +1097,6 @@ impl Config { | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } - | Subcommand::Suggest { .. } | Subcommand::Vendor { .. } | Subcommand::Perf { .. } => {} } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 155b6f587589..1547ca444943 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -481,13 +481,6 @@ Arguments: #[arg(value_name = "|hook|editor|link")] profile: Option, }, - /// Suggest a subset of tests to run, based on modified files - #[command(long_about = "\n")] - Suggest { - /// run suggested tests - #[arg(long)] - run: bool, - }, /// Vendor dependencies Vendor { /// Additional `Cargo.toml` to sync and vendor @@ -518,7 +511,6 @@ impl Subcommand { Subcommand::Install => Kind::Install, Subcommand::Run { .. } => Kind::Run, Subcommand::Setup { .. } => Kind::Setup, - Subcommand::Suggest { .. } => Kind::Suggest, Subcommand::Vendor { .. } => Kind::Vendor, Subcommand::Perf { .. } => Kind::Perf, } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index f2119e84cce7..b39d464493e5 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -216,7 +216,6 @@ than building it. build.config.cmd, Subcommand::Clean { .. } | Subcommand::Check { .. } - | Subcommand::Suggest { .. } | Subcommand::Format { .. } | Subcommand::Setup { .. } ); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 66a164703b7f..44be51815c7c 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -651,11 +651,9 @@ impl Build { // Handle hard-coded subcommands. { #[cfg(feature = "tracing")] - let _hardcoded_span = span!( - tracing::Level::DEBUG, - "handling hardcoded subcommands (Format, Suggest, Perf)" - ) - .entered(); + let _hardcoded_span = + span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Perf)") + .entered(); match &self.config.cmd { Subcommand::Format { check, all } => { @@ -666,9 +664,6 @@ impl Build { &self.config.paths, ); } - Subcommand::Suggest { run } => { - return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run); - } Subcommand::Perf(args) => { return core::build_steps::perf::perf(&builder::Builder::new(self), args); } diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index dcafeb80f90c..778591189a3c 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -67,7 +67,6 @@ pub fn fill_compilers(build: &mut Build) { // We don't need to check cross targets for these commands. crate::Subcommand::Clean { .. } | crate::Subcommand::Check { .. } - | crate::Subcommand::Suggest { .. } | crate::Subcommand::Format { .. } | crate::Subcommand::Setup { .. } => { build.hosts.iter().cloned().chain(iter::once(build.host_target)).collect() diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index 862c44496241..9b1ccc32cb61 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -43,7 +43,7 @@ pub(crate) struct BuildMetrics { state: RefCell, } -/// NOTE: this isn't really cloning anything, but `x suggest` doesn't need metrics so this is probably ok. +// NOTE: this isn't really cloning anything, but necessary for `Build: Clone`. impl Clone for BuildMetrics { fn clone(&self) -> Self { Self::init() diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml deleted file mode 100644 index d6f86078d7ef..000000000000 --- a/src/tools/suggest-tests/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "suggest-tests" -version = "0.1.0" -edition = "2021" - -[dependencies] -glob = "0.3.0" -build_helper = { version = "0.1.0", path = "../../build_helper" } diff --git a/src/tools/suggest-tests/src/dynamic_suggestions.rs b/src/tools/suggest-tests/src/dynamic_suggestions.rs deleted file mode 100644 index f09720f1c91f..000000000000 --- a/src/tools/suggest-tests/src/dynamic_suggestions.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::path::Path; - -use crate::Suggestion; - -type DynamicSuggestion = fn(&Path) -> Vec; - -pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[ - |path: &Path| -> Vec { - if path.starts_with("compiler/") || path.starts_with("library/") { - let path = path.components().take(2).collect::>(); - - vec![Suggestion::with_single_path( - "test", - None, - &format!( - "{}/{}", - path[0].as_os_str().to_str().unwrap(), - path[1].as_os_str().to_str().unwrap() - ), - )] - } else { - Vec::new() - } - }, - |path: &Path| -> Vec { - if path.starts_with("compiler/rustc_pattern_analysis") { - vec![Suggestion::new("test", None, &["tests/ui", "--test-args", "pattern"])] - } else { - Vec::new() - } - }, -]; diff --git a/src/tools/suggest-tests/src/lib.rs b/src/tools/suggest-tests/src/lib.rs deleted file mode 100644 index cc1288c6b72e..000000000000 --- a/src/tools/suggest-tests/src/lib.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::fmt::{self, Display}; -use std::path::Path; - -use dynamic_suggestions::DYNAMIC_SUGGESTIONS; -use glob::Pattern; -use static_suggestions::static_suggestions; - -mod dynamic_suggestions; -mod static_suggestions; - -#[cfg(test)] -mod tests; - -macro_rules! sug { - ($cmd:expr) => { - Suggestion::new($cmd, None, &[]) - }; - - ($cmd:expr, $paths:expr) => { - Suggestion::new($cmd, None, $paths.as_slice()) - }; - - ($cmd:expr, $stage:expr, $paths:expr) => { - Suggestion::new($cmd, Some($stage), $paths.as_slice()) - }; -} - -pub(crate) use sug; - -pub fn get_suggestions>(modified_files: &[T]) -> Vec { - let mut suggestions = Vec::new(); - - // static suggestions - for (globs, sugs) in static_suggestions().iter() { - let globs = globs - .iter() - .map(|glob| Pattern::new(glob).expect("Found invalid glob pattern!")) - .collect::>(); - let matches_some_glob = |file: &str| globs.iter().any(|glob| glob.matches(file)); - - if modified_files.iter().map(AsRef::as_ref).any(matches_some_glob) { - suggestions.extend_from_slice(sugs); - } - } - - // dynamic suggestions - for sug in DYNAMIC_SUGGESTIONS { - for file in modified_files { - let sugs = sug(Path::new(file.as_ref())); - - suggestions.extend_from_slice(&sugs); - } - } - - suggestions.sort(); - suggestions.dedup(); - - suggestions -} - -#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] -pub struct Suggestion { - pub cmd: String, - pub stage: Option, - pub paths: Vec, -} - -impl Suggestion { - pub fn new(cmd: &str, stage: Option, paths: &[&str]) -> Self { - Self { cmd: cmd.to_owned(), stage, paths: paths.iter().map(|p| p.to_string()).collect() } - } - - pub fn with_single_path(cmd: &str, stage: Option, path: &str) -> Self { - Self::new(cmd, stage, &[path]) - } -} - -impl Display for Suggestion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "{} ", self.cmd)?; - - for path in &self.paths { - write!(f, "{} ", path)?; - } - - if let Some(stage) = self.stage { - write!(f, "{}", stage)?; - } else { - // write a sentinel value here (in place of a stage) to be consumed - // by the shim in bootstrap, it will be read and ignored. - write!(f, "N/A")?; - } - - Ok(()) - } -} diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs deleted file mode 100644 index d84f8e9fa1ba..000000000000 --- a/src/tools/suggest-tests/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::process::ExitCode; - -use build_helper::git::{GitConfig, get_git_modified_files}; -use suggest_tests::get_suggestions; - -fn main() -> ExitCode { - let modified_files = get_git_modified_files( - &GitConfig { - nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"), - git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"), - }, - None, - &Vec::new(), - ); - let modified_files = match modified_files { - Ok(files) => files, - Err(err) => { - eprintln!("Could not get modified files from git: \"{err}\""); - return ExitCode::FAILURE; - } - }; - - let suggestions = get_suggestions(&modified_files); - - for sug in &suggestions { - println!("{sug}"); - } - - ExitCode::SUCCESS -} - -fn env(key: &str) -> String { - match std::env::var(key) { - Ok(var) => var, - Err(err) => { - eprintln!("suggest-tests: failed to read environment variable {key}: {err}"); - std::process::exit(1); - } - } -} diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs deleted file mode 100644 index d363d583b546..000000000000 --- a/src/tools/suggest-tests/src/static_suggestions.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::sync::OnceLock; - -use crate::{Suggestion, sug}; - -// FIXME: perhaps this could use `std::lazy` when it is stabilized -macro_rules! static_suggestions { - ($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => { - pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec)] - { - static S: OnceLock, Vec)>> = OnceLock::new(); - S.get_or_init(|| vec![ $( (vec![ $($glob),* ], vec![ $($suggestion),* ]) ),*]) - } - } -} - -static_suggestions! { - ["*.md"] => [ - sug!("test", 0, ["linkchecker"]), - ], - - ["compiler/*"] => [ - sug!("check"), - sug!("test", 1, ["tests/ui", "tests/run-make"]), - ], - - ["compiler/rustc_mir_transform/*"] => [ - sug!("test", 1, ["mir-opt"]), - ], - - [ - "compiler/rustc_mir_transform/src/coverage/*", - "compiler/rustc_codegen_llvm/src/coverageinfo/*", - ] => [ - sug!("test", 1, ["coverage"]), - ], - - ["src/librustdoc/*"] => [ - sug!("test", 1, ["rustdoc"]), - ], -} diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs deleted file mode 100644 index b4149136fa30..000000000000 --- a/src/tools/suggest-tests/src/tests.rs +++ /dev/null @@ -1,21 +0,0 @@ -macro_rules! sugg_test { - ( $( $name:ident: $paths:expr => $suggestions:expr ),* ) => { - $( - #[test] - fn $name() { - let suggestions = crate::get_suggestions(&$paths).into_iter().map(|s| s.to_string()).collect::>(); - assert_eq!(suggestions, $suggestions); - } - )* - }; -} - -sugg_test! { - test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] => - ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test tests/ui tests/run-make 1"], - - test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"], - - test_rustdoc_and_libstd: ["src/librustdoc/src/lib.rs", "library/std/src/lib.rs"] => - ["test library/std N/A", "test rustdoc 1"] -} From 647c051feca0a8b2e7e63bd1009917ea963b8bc7 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:53:58 +0800 Subject: [PATCH 35/64] Regenerate completions after removing `./x suggest` --- src/etc/completions/x.fish | 37 ------- src/etc/completions/x.ps1 | 44 -------- src/etc/completions/x.py.fish | 37 ------- src/etc/completions/x.py.ps1 | 44 -------- src/etc/completions/x.py.sh | 191 +--------------------------------- src/etc/completions/x.py.zsh | 51 --------- src/etc/completions/x.sh | 191 +--------------------------------- src/etc/completions/x.zsh | 51 --------- 8 files changed, 2 insertions(+), 644 deletions(-) diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index d3da1f353e24..28a228d54645 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -73,7 +73,6 @@ complete -c x -n "__fish_x_needs_command" -a "dist" -d 'Build distribution artif complete -c x -n "__fish_x_needs_command" -a "install" -d 'Install distribution artifacts' complete -c x -n "__fish_x_needs_command" -a "run" -d 'Run tools contained in this repository' complete -c x -n "__fish_x_needs_command" -a "setup" -d 'Set up the environment for development' -complete -c x -n "__fish_x_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x -n "__fish_x_needs_command" -a "vendor" -d 'Vendor dependencies' complete -c x -n "__fish_x_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x -n "__fish_x_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F @@ -599,42 +598,6 @@ complete -c x -n "__fish_x_using_subcommand setup" -l enable-bolt-settings -d 'E complete -c x -n "__fish_x_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l host -d 'host targets to build' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l target -d 'target targets to build' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" -complete -c x -n "__fish_x_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F -complete -c x -n "__fish_x_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r -complete -c x -n "__fish_x_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f -complete -c x -n "__fish_x_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" -complete -c x -n "__fish_x_using_subcommand suggest" -l run -d 'run suggested tests' -complete -c x -n "__fish_x_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' -complete -c x -n "__fish_x_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation' -complete -c x -n "__fish_x_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones' -complete -c x -n "__fish_x_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything' -complete -c x -n "__fish_x_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' -complete -c x -n "__fish_x_using_subcommand suggest" -l json-output -d 'use message-format=json' -complete -c x -n "__fish_x_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)' -complete -c x -n "__fish_x_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' -complete -c x -n "__fish_x_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' -complete -c x -n "__fish_x_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' -complete -c x -n "__fish_x_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x -n "__fish_x_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' -complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index b5b59c58bbae..0c9b38282731 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') - [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`') break @@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } - 'x;suggest' { - [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') - [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') - [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') - [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') - [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') - [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') - [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format') - [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') - [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') - [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') - [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') - [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') - [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') - [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') - [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') - [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') - [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') - [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') - [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests') - [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') - [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') - [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') - [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json') - [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)') - [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') - [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') - [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') - [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - break - } 'x;vendor' { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index da7680a879de..43ae7424e27b 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -73,7 +73,6 @@ complete -c x.py -n "__fish_x.py_needs_command" -a "dist" -d 'Build distribution complete -c x.py -n "__fish_x.py_needs_command" -a "install" -d 'Install distribution artifacts' complete -c x.py -n "__fish_x.py_needs_command" -a "run" -d 'Run tools contained in this repository' complete -c x.py -n "__fish_x.py_needs_command" -a "setup" -d 'Set up the environment for development' -complete -c x.py -n "__fish_x.py_needs_command" -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' complete -c x.py -n "__fish_x.py_needs_command" -a "vendor" -d 'Vendor dependencies' complete -c x.py -n "__fish_x.py_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x.py -n "__fish_x.py_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F @@ -599,42 +598,6 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l enable-bolt-settings complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-stage0-validation -d 'Skip stage0 compiler validation' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l host -d 'host targets to build' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l target -d 'target targets to build' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip -d 'build paths to skip' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rustc-error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny\t'',warn\t'',default\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always\t'',never\t'',auto\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l set -d 'override options in bootstrap.toml' -r -f -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l run -d 'run suggested tests' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s i -l incremental -d 'use incremental compilation' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l include-default-paths -d 'include default paths in addition to the provided ones' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dry-run -d 'dry run; don\'t build anything' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l json-output -d 'use message-format=json' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l compile-time-deps -d 'only build proc-macros and build scripts (for rust-analyzer)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-stage0-validation -d 'Skip stage0 compiler validation' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l skip-std-check-if-no-download-rustc -d 'Skip checking the standard library if `rust.download-rustc` isn\'t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers' -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 3fc8e7d5bbd9..4311e383d640 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -74,7 +74,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') - [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') [CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies') [CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using `rustc-perf`') break @@ -700,49 +699,6 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } - 'x.py;suggest' { - [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') - [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') - [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') - [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') - [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') - [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') - [CompletionResult]::new('--rustc-error-format', '--rustc-error-format', [CompletionResultType]::ParameterName, 'rustc error format') - [CompletionResult]::new('--on-fail', '--on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') - [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') - [CompletionResult]::new('--keep-stage', '--keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--keep-stage-std', '--keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') - [CompletionResult]::new('--src', '--src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') - [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--jobs', '--jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') - [CompletionResult]::new('--warnings', '--warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') - [CompletionResult]::new('--color', '--color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') - [CompletionResult]::new('--rust-profile-generate', '--rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') - [CompletionResult]::new('--rust-profile-use', '--rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') - [CompletionResult]::new('--llvm-profile-use', '--llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') - [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') - [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') - [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') - [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'run suggested tests') - [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') - [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--incremental', '--incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') - [CompletionResult]::new('--include-default-paths', '--include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') - [CompletionResult]::new('--dry-run', '--dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') - [CompletionResult]::new('--dump-bootstrap-shims', '--dump-bootstrap-shims', [CompletionResultType]::ParameterName, 'Indicates whether to dump the work done from bootstrap shims') - [CompletionResult]::new('--json-output', '--json-output', [CompletionResultType]::ParameterName, 'use message-format=json') - [CompletionResult]::new('--compile-time-deps', '--compile-time-deps', [CompletionResultType]::ParameterName, 'only build proc-macros and build scripts (for rust-analyzer)') - [CompletionResult]::new('--bypass-bootstrap-lock', '--bypass-bootstrap-lock', [CompletionResultType]::ParameterName, 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)') - [CompletionResult]::new('--llvm-profile-generate', '--llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') - [CompletionResult]::new('--enable-bolt-settings', '--enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') - [CompletionResult]::new('--skip-stage0-validation', '--skip-stage0-validation', [CompletionResultType]::ParameterName, 'Skip stage0 compiler validation') - [CompletionResult]::new('--skip-std-check-if-no-download-rustc', '--skip-std-check-if-no-download-rustc', [CompletionResultType]::ParameterName, 'Skip checking the standard library if `rust.download-rustc` isn''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers') - [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') - break - } 'x.py;vendor' { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 8f13de282fb7..f31bdb58dc44 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -54,9 +54,6 @@ _x.py() { x.py,setup) cmd="x.py__setup" ;; - x.py,suggest) - cmd="x.py__suggest" - ;; x.py,test) cmd="x.py__test" ;; @@ -85,7 +82,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3877,192 +3874,6 @@ _x.py() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - x.py__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --config) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --build-dir) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --build) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --host) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --target) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --exclude) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --skip) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --rustc-error-format) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --on-fail) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage-std) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --src) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --jobs) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - -j) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --warnings) - COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) - return 0 - ;; - --rust-profile-generate) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --rust-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --llvm-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --reproducible-artifact) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --set) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --ci) - COMPREPLY=($(compgen -W "true false" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; x.py__test) opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 60ce90021162..aff35b31e212 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; -(suggest) -_arguments "${_arguments_options[@]}" : \ -'--config=[TOML configuration file for build]:FILE:_files' \ -'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[host target of the stage0 compiler]:BUILD:' \ -'--host=[host targets to build]:HOST:' \ -'--target=[target targets to build]:TARGET:' \ -'*--exclude=[build paths to exclude]:PATH:_files' \ -'*--skip=[build paths to skip]:PATH:_files' \ -'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \ -'--on-fail=[command to run on failure]:CMD:_cmdstring' \ -'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \ -'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'--src=[path to the root of the rust checkout]:DIR:_files -/' \ -'-j+[number of jobs to run in parallel]:JOBS:' \ -'--jobs=[number of jobs to run in parallel]:JOBS:' \ -'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ -'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ -'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ -'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ -'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ -'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ -'*--set=[override options in bootstrap.toml]:section.option=value:' \ -'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ -'--run[run suggested tests]' \ -'*-v[use verbose output (-vv for very verbose)]' \ -'*--verbose[use verbose output (-vv for very verbose)]' \ -'-i[use incremental compilation]' \ -'--incremental[use incremental compilation]' \ -'--include-default-paths[include default paths in addition to the provided ones]' \ -'--dry-run[dry run; don'\''t build anything]' \ -'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ -'--json-output[use message-format=json]' \ -'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \ -'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ -'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ -'--enable-bolt-settings[Enable BOLT link flags]' \ -'--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::paths -- paths for the subcommand:_files' \ -&& ret=0 -;; (vendor) _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ @@ -1120,7 +1075,6 @@ _x.py_commands() { 'install:Install distribution artifacts' \ 'run:Run tools contained in this repository' \ 'setup:Set up the environment for development' \ -'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \ ) @@ -1227,11 +1181,6 @@ _x.py__setup_commands() { local commands; commands=() _describe -t commands 'x.py setup commands' commands "$@" } -(( $+functions[_x.py__suggest_commands] )) || -_x.py__suggest_commands() { - local commands; commands=() - _describe -t commands 'x.py suggest commands' commands "$@" -} (( $+functions[_x.py__test_commands] )) || _x.py__test_commands() { local commands; commands=() diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index f6ecf4cebf49..927d8f7661cd 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -54,9 +54,6 @@ _x() { x,setup) cmd="x__setup" ;; - x,suggest) - cmd="x__suggest" - ;; x,test) cmd="x__test" ;; @@ -85,7 +82,7 @@ _x() { case "${cmd}" in x) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup suggest vendor perf" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]... build check clippy fix fmt doc test miri bench clean dist install run setup vendor perf" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3877,192 +3874,6 @@ _x() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - x__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --config) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --build-dir) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --build) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --host) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --target) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --exclude) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --skip) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --rustc-error-format) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --on-fail) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --keep-stage-std) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --src) - COMPREPLY=() - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o plusdirs - fi - return 0 - ;; - --jobs) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - -j) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --warnings) - COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) - return 0 - ;; - --rust-profile-generate) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --rust-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --llvm-profile-use) - local oldifs - if [ -n "${IFS+x}" ]; then - oldifs="$IFS" - fi - IFS=$'\n' - COMPREPLY=($(compgen -f "${cur}")) - if [ -n "${oldifs+x}" ]; then - IFS="$oldifs" - fi - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o filenames - fi - return 0 - ;; - --reproducible-artifact) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --set) - COMPREPLY=("${cur}") - if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then - compopt -o nospace - fi - return 0 - ;; - --ci) - COMPREPLY=($(compgen -W "true false" -- "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; x__test) opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 452a26fef07e..28ad00f3a0de 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -715,51 +715,6 @@ _arguments "${_arguments_options[@]}" : \ '*::paths -- paths for the subcommand:_files' \ && ret=0 ;; -(suggest) -_arguments "${_arguments_options[@]}" : \ -'--config=[TOML configuration file for build]:FILE:_files' \ -'--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[host target of the stage0 compiler]:BUILD:' \ -'--host=[host targets to build]:HOST:' \ -'--target=[target targets to build]:TARGET:' \ -'*--exclude=[build paths to exclude]:PATH:_files' \ -'*--skip=[build paths to skip]:PATH:_files' \ -'--rustc-error-format=[rustc error format]:RUSTC_ERROR_FORMAT:' \ -'--on-fail=[command to run on failure]:CMD:_cmdstring' \ -'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:' \ -'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:' \ -'--src=[path to the root of the rust checkout]:DIR:_files -/' \ -'-j+[number of jobs to run in parallel]:JOBS:' \ -'--jobs=[number of jobs to run in parallel]:JOBS:' \ -'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ -'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ -'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ -'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ -'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ -'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ -'*--set=[override options in bootstrap.toml]:section.option=value:' \ -'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ -'--run[run suggested tests]' \ -'*-v[use verbose output (-vv for very verbose)]' \ -'*--verbose[use verbose output (-vv for very verbose)]' \ -'-i[use incremental compilation]' \ -'--incremental[use incremental compilation]' \ -'--include-default-paths[include default paths in addition to the provided ones]' \ -'--dry-run[dry run; don'\''t build anything]' \ -'--dump-bootstrap-shims[Indicates whether to dump the work done from bootstrap shims]' \ -'--json-output[use message-format=json]' \ -'--compile-time-deps[only build proc-macros and build scripts (for rust-analyzer)]' \ -'--bypass-bootstrap-lock[Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)]' \ -'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ -'--enable-bolt-settings[Enable BOLT link flags]' \ -'--skip-stage0-validation[Skip stage0 compiler validation]' \ -'--skip-std-check-if-no-download-rustc[Skip checking the standard library if \`rust.download-rustc\` isn'\''t available. This is mostly for RA as building the stage1 compiler to check the library tree on each code change might be too much for some computers]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -'*::paths -- paths for the subcommand:_files' \ -&& ret=0 -;; (vendor) _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ @@ -1120,7 +1075,6 @@ _x_commands() { 'install:Install distribution artifacts' \ 'run:Run tools contained in this repository' \ 'setup:Set up the environment for development' \ -'suggest:Suggest a subset of tests to run, based on modified files' \ 'vendor:Vendor dependencies' \ 'perf:Perform profiling and benchmarking of the compiler using \`rustc-perf\`' \ ) @@ -1227,11 +1181,6 @@ _x__setup_commands() { local commands; commands=() _describe -t commands 'x setup commands' commands "$@" } -(( $+functions[_x__suggest_commands] )) || -_x__suggest_commands() { - local commands; commands=() - _describe -t commands 'x suggest commands' commands "$@" -} (( $+functions[_x__test_commands] )) || _x__test_commands() { local commands; commands=() From 186afbb911b561d7f10efa9c5a729715f2db4131 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:58:49 +0800 Subject: [PATCH 36/64] Remove mentions of `./x suggest` and `suggest-tests` in rustc-dev-guide --- src/doc/rustc-dev-guide/src/SUMMARY.md | 1 - .../src/building/quickstart.md | 3 - .../rustc-dev-guide/src/building/suggested.md | 17 ------ .../src/tests/suggest-tests.md | 59 ------------------- 4 files changed, 80 deletions(-) delete mode 100644 src/doc/rustc-dev-guide/src/tests/suggest-tests.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 7f2f32c62ffb..651e2925ad50 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -35,7 +35,6 @@ - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md) - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md) - [Performance testing](./tests/perf.md) - - [Suggest tests tool](./tests/suggest-tests.md) - [Misc info](./tests/misc.md) - [Debugging the compiler](./compiler-debugging.md) - [Using the tracing/logging instrumentation](./tracing.md) diff --git a/src/doc/rustc-dev-guide/src/building/quickstart.md b/src/doc/rustc-dev-guide/src/building/quickstart.md index 9a8ab353e029..97314d803695 100644 --- a/src/doc/rustc-dev-guide/src/building/quickstart.md +++ b/src/doc/rustc-dev-guide/src/building/quickstart.md @@ -61,9 +61,6 @@ and check the output. Use `--bless` if you've made a change and want to update the `.stderr` files with the new output. -> `./x suggest` can also be helpful for suggesting which tests to run after a -> change. - Congrats, you are now ready to make a change to the compiler! If you have more questions, [the full chapter](./how-to-build-and-run.md) might contain the answers, and if it doesn't, feel free to ask for help on diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index bfb2f4d1084a..7f626314f718 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -270,23 +270,6 @@ run the tests at some later time. You can then use `git bisect` to track down is that you are left with a fairly fine-grained set of commits at the end, all of which build and pass tests. This often helps reviewing. -## `x suggest` - -The `x suggest` subcommand suggests (and runs) a subset of the extensive -`rust-lang/rust` tests based on files you have changed. This is especially -useful for new contributors who have not mastered the arcane `x` flags yet and -more experienced contributors as a shorthand for reducing mental effort. In all -cases it is useful not to run the full tests (which can take on the order of -tens of minutes) and just run a subset which are relevant to your changes. For -example, running `tidy` and `linkchecker` is useful when editing Markdown files, -whereas UI tests are much less likely to be helpful. While `x suggest` is a -useful tool, it does not guarantee perfect coverage (just as PR CI isn't a -substitute for bors). See the [dedicated chapter](../tests/suggest-tests.md) for -more information and contribution instructions. - -Please note that `x suggest` is in a beta state currently and the tests that it -will suggest are limited. - ## Configuring `rustup` to use nightly Some parts of the bootstrap process uses pinned, nightly versions of tools like diff --git a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md b/src/doc/rustc-dev-guide/src/tests/suggest-tests.md deleted file mode 100644 index 663e8a5af3b9..000000000000 --- a/src/doc/rustc-dev-guide/src/tests/suggest-tests.md +++ /dev/null @@ -1,59 +0,0 @@ -# Suggest tests tool - -This chapter is about the internals of and contribution instructions for the -`suggest-tests` tool. For a high-level overview of the tool, see [this -section](../building/suggested.md#x-suggest). This tool is currently in a beta -state and is tracked by [this](https://github.com/rust-lang/rust/issues/109933) -issue on Github. Currently the number of tests it will suggest are very limited -in scope, we are looking to expand this (contributions welcome!). - -## Internals - -The tool is defined in a separate crate -([`src/tools/suggest-tests`](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests)) -which outputs suggestions which are parsed by a shim in bootstrap -([`src/bootstrap/src/core/build_steps/suggest.rs`](https://github.com/rust-lang/rust/blob/master/src/bootstrap/src/core/build_steps/suggest.rs)). -The only notable thing the bootstrap shim does is (when invoked with the `--run` -flag) use bootstrap's internal mechanisms to create a new `Builder` and uses it -to invoke the suggested commands. The `suggest-tests` crate is where the fun -happens, two kinds of suggestions are defined: "static" and "dynamic" -suggestions. - -### Static suggestions - -Defined -[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/static_suggestions.rs). -Static suggestions are simple: they are just -[globs](https://crates.io/crates/glob) which map to a `x` command. In -`suggest-tests`, this is implemented with a simple `macro_rules` macro. - -### Dynamic suggestions - -Defined -[here](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/dynamic_suggestions.rs). -These are more complicated than static suggestions and are implemented as -functions with the following signature: `fn(&Path) -> Vec`. In other -words, each suggestion takes a path to a modified file and (after running -arbitrary Rust code) can return any number of suggestions, or none. Dynamic -suggestions are useful for situations where fine-grained control over -suggestions is needed. For example, modifications to the `compiler/xyz/` path -should trigger the `x test compiler/xyz` suggestion. In the future, dynamic -suggestions might even read file contents to determine if (what) tests should -run. - -## Adding a suggestion - -The following steps should serve as a rough guide to add suggestions to -`suggest-tests` (very welcome!): - -1. Determine the rules for your suggestion. Is it simple and operates only on a - single path or does it match globs? Does it need fine-grained control over - the resulting command or does "one size fit all"? -2. Based on the previous step, decide if your suggestion should be implemented - as either static or dynamic. -3. Implement the suggestion. If it is dynamic then a test is highly recommended, - to verify that your logic is correct and to give an example of the - suggestion. See the - [tests.rs](https://github.com/rust-lang/rust/blob/master/src/tools/suggest-tests/src/tests.rs) - file. -4. Open a PR implementing your suggestion. **(TODO: add example PR)** From 0a899e0e8ad99d2e7afd1dd8e8466d6a14a04787 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Tue, 8 Jul 2025 17:59:54 +0800 Subject: [PATCH 37/64] Update triagebot autolabel --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 125617fce74f..714bb8d4b974 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -506,7 +506,6 @@ trigger_files = [ "src/tools/remote-test-server", "src/tools/remote-test-client", "src/tools/rustdoc-gui-test", - "src/tools/suggest-tests", ] [autolabel."A-tidy"] From 1669ba055c1e02c459df42926f8762bc27b8ada8 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 14 Jul 2025 19:01:40 +0200 Subject: [PATCH 38/64] Update books --- src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index ef1ce8f87a8b..b2d1a0821e12 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ef1ce8f87a8b18feb1b6a9cf9a4939a79bde6795 +Subproject commit b2d1a0821e12a676b496d61891b8e3d374a8e832 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 41f688a598a5..fe88fbb68391 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 41f688a598a5022b749e23d37f3c524f6a0b28e1 +Subproject commit fe88fbb68391a465680dd91109f0a151a1676f3e diff --git a/src/doc/nomicon b/src/doc/nomicon index 8b61acfaea82..3ff384320598 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8b61acfaea822e9ac926190bc8f15791c33336e8 +Subproject commit 3ff384320598bbe8d8cfe5cb8f18f78a3a3e6b15 diff --git a/src/doc/reference b/src/doc/reference index e9fc99f10784..1f45bd41fa6c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit e9fc99f107840813916f62e16b3f6d9556e1f2d8 +Subproject commit 1f45bd41fa6c17b7c048ed6bfe5f168c4311206a diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 288b4e4948ad..e386be5f44af 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 288b4e4948add43f387cad35adc7b1c54ca6fe12 +Subproject commit e386be5f44af711854207c11fdd61bb576270b04 From 9bdd3b0ee6a6fd5914fea0f56f3b754410733e53 Mon Sep 17 00:00:00 2001 From: Paul Murphy Date: Thu, 10 Jul 2025 10:58:58 -0500 Subject: [PATCH 39/64] Don't always panic if WASI_SDK_PATH is not set when detecting compilers They are not always needed when building std, as is the case when packaging on Fedora. Panic if building from CI, but warn otherwise. --- src/bootstrap/src/utils/cc_detect.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index dcafeb80f90c..2569f95e3efa 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -221,10 +221,15 @@ fn default_compiler( } t if t.contains("-wasi") => { - let root = build - .wasi_sdk_path - .as_ref() - .expect("WASI_SDK_PATH mut be configured for a -wasi target"); + let root = if let Some(path) = build.wasi_sdk_path.as_ref() { + path + } else { + if build.config.is_running_on_ci { + panic!("ERROR: WASI_SDK_PATH must be configured for a -wasi target on CI"); + } + println!("WARNING: WASI_SDK_PATH not set, using default cc/cxx compiler"); + return None; + }; let compiler = match compiler { Language::C => format!("{t}-clang"), Language::CPlusPlus => format!("{t}-clang++"), From d0153f5872c484dff2a4b0ef6cad45c1f14fa1b7 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 14 Jul 2025 11:03:16 +0200 Subject: [PATCH 40/64] update `cfg_select!` documentation and make internal terminology consistent Co-authored-by: Travis Cross --- compiler/rustc_builtin_macros/messages.ftl | 6 +++--- compiler/rustc_builtin_macros/src/cfg_select.rs | 16 ++++++++-------- compiler/rustc_parse/src/parser/cfg_select.rs | 10 ++++++---- library/core/src/macros/mod.rs | 16 +++++++--------- tests/ui/macros/cfg_select.rs | 7 +++++-- tests/ui/macros/cfg_select.stderr | 14 ++++++++++---- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 183927edb022..ae186d744c40 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -81,11 +81,11 @@ builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a l builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified -builtin_macros_cfg_select_no_matches = none of the rules in this `cfg_select` evaluated to true +builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true -builtin_macros_cfg_select_unreachable = unreachable rule +builtin_macros_cfg_select_unreachable = unreachable predicate .label = always matches - .label2 = this rules is never reached + .label2 = this predicate is never reached builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized` diff --git a/compiler/rustc_builtin_macros/src/cfg_select.rs b/compiler/rustc_builtin_macros/src/cfg_select.rs index 2dc387d5866a..f22d5f255c29 100644 --- a/compiler/rustc_builtin_macros/src/cfg_select.rs +++ b/compiler/rustc_builtin_macros/src/cfg_select.rs @@ -1,12 +1,12 @@ use rustc_ast::tokenstream::TokenStream; use rustc_attr_parsing as attr; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; -use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectRule, parse_cfg_select}; +use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select}; use rustc_span::{Ident, Span, sym}; use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable}; -/// Selects the first arm whose rule evaluates to true. +/// Selects the first arm whose predicate evaluates to true. fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> { for (cfg, tt, arm_span) in branches.reachable { if attr::cfg_matches( @@ -30,11 +30,11 @@ pub(super) fn expand_cfg_select<'cx>( ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) { Ok(branches) => { if let Some((underscore, _, _)) = branches.wildcard { - // Warn for every unreachable rule. We store the fully parsed branch for rustfmt. - for (rule, _, _) in &branches.unreachable { - let span = match rule { - CfgSelectRule::Wildcard(underscore) => underscore.span, - CfgSelectRule::Cfg(cfg) => cfg.span(), + // Warn for every unreachable predicate. We store the fully parsed branch for rustfmt. + for (predicate, _, _) in &branches.unreachable { + let span = match predicate { + CfgSelectPredicate::Wildcard(underscore) => underscore.span, + CfgSelectPredicate::Cfg(cfg) => cfg.span(), }; let err = CfgSelectUnreachable { span, wildcard_span: underscore.span }; ecx.dcx().emit_warn(err); @@ -50,7 +50,7 @@ pub(super) fn expand_cfg_select<'cx>( Ident::with_dummy_span(sym::cfg_select), ); } else { - // Emit a compiler error when none of the rules matched. + // Emit a compiler error when none of the predicates matched. let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp }); DummyResult::any(sp, guar) } diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index 24a05afff4ac..2c6fb224d70d 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use crate::exp; use crate::parser::Parser; -pub enum CfgSelectRule { +pub enum CfgSelectPredicate { Cfg(MetaItemInner), Wildcard(Token), } @@ -20,7 +20,7 @@ pub struct CfgSelectBranches { pub wildcard: Option<(Token, TokenStream, Span)>, /// All branches after the first wildcard, including further wildcards. /// These branches are kept for formatting. - pub unreachable: Vec<(CfgSelectRule, TokenStream, Span)>, + pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, } /// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where @@ -52,7 +52,7 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.wildcard = Some((underscore, tts, span)), Some(_) => { - branches.unreachable.push((CfgSelectRule::Wildcard(underscore), tts, span)) + branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span)) } } } else { @@ -64,7 +64,9 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.reachable.push((meta_item, tts, span)), - Some(_) => branches.unreachable.push((CfgSelectRule::Cfg(meta_item), tts, span)), + Some(_) => { + branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span)) + } } } } diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 6b9cbb064358..1b6dbc2f428f 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -196,16 +196,14 @@ pub macro assert_matches { }, } -/// A macro for defining `#[cfg]` match-like statements. +/// Selects code at compile-time based on `cfg` predicates. /// -/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of -/// `#[cfg]` cases, emitting the implementation which matches first. +/// This macro evaluates, at compile-time, a series of `cfg` predicates, +/// selects the first that is true, and emits the code guarded by that +/// predicate. The code guarded by other predicates is not emitted. /// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code -/// without having to rewrite each clause multiple times. -/// -/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when -/// all previous declarations do not evaluate to true. +/// An optional trailing `_` wildcard can be used to specify a fallback. If +/// none of the predicates are true, a [`compile_error`] is emitted. /// /// # Example /// @@ -225,7 +223,7 @@ pub macro assert_matches { /// } /// ``` /// -/// If desired, it is possible to return expressions through the use of surrounding braces: +/// The `cfg_select!` macro can also be used in expression position: /// /// ``` /// #![feature(cfg_select)] diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index a4d94836a09a..461d2e0e8c1f 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -18,10 +18,13 @@ fn arm_rhs_must_be_in_braces() -> i32 { cfg_select! { _ => {} true => {} - //~^ WARN unreachable rule + //~^ WARN unreachable predicate } cfg_select! { - //~^ ERROR none of the rules in this `cfg_select` evaluated to true + //~^ ERROR none of the predicates in this `cfg_select` evaluated to true false => {} } + +cfg_select! {} +//~^ ERROR none of the predicates in this `cfg_select` evaluated to true diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index fef5e95a6bce..6c18a7c189dc 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -4,15 +4,15 @@ error: expected `{`, found `1` LL | true => 1 | ^ expected `{` -warning: unreachable rule +warning: unreachable predicate --> $DIR/cfg_select.rs:20:5 | LL | _ => {} | - always matches LL | true => {} - | ^^^^ this rules is never reached + | ^^^^ this predicate is never reached -error: none of the rules in this `cfg_select` evaluated to true +error: none of the predicates in this `cfg_select` evaluated to true --> $DIR/cfg_select.rs:24:1 | LL | / cfg_select! { @@ -21,5 +21,11 @@ LL | | false => {} LL | | } | |_^ -error: aborting due to 2 previous errors; 1 warning emitted +error: none of the predicates in this `cfg_select` evaluated to true + --> $DIR/cfg_select.rs:29:1 + | +LL | cfg_select! {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted From f0d0afab8e3c37286d261467df053a9a1635b91a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 13 Jul 2025 11:56:13 +0200 Subject: [PATCH 41/64] Port `#[pointee]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_data_structures/src/attributes.rs | 3 +++ .../rustc_attr_data_structures/src/encode_cross_crate.rs | 1 + compiler/rustc_attr_parsing/src/attributes/traits.rs | 7 +++++++ compiler/rustc_attr_parsing/src/context.rs | 5 +++-- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- 6 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9b14ed88978b..a5c04970e812 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -349,6 +349,9 @@ pub enum AttributeKind { /// Represents `#[path]` Path(Symbol, Span), + /// Represents `#[pointee]` + Pointee(Span), + /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). PubTransparent(Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 494b570c86c7..3e2dc0a15b2f 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -57,6 +57,7 @@ impl AttributeKind { ParenSugar(..) => No, PassByValue(..) => Yes, Path(..) => No, + Pointee(..) => No, PubTransparent(..) => Yes, Repr { .. } => No, RustcLayoutScalarValidRangeEnd(..) => Yes, diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index ee8a33ae9c43..d5e088effd51 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -145,3 +145,10 @@ impl NoArgsAttributeParser for FundamentalParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental; } + +pub(crate) struct PointeeParser; +impl NoArgsAttributeParser for PointeeParser { + const PATH: &[Symbol] = &[sym::pointee]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6c70f2ee4ee0..61638001a2bc 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -48,8 +48,8 @@ use crate::attributes::test_attrs::IgnoreParser; use crate::attributes::traits::{ AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, - ParenSugarParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser, - UnsafeSpecializationMarkerParser, + ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, + TypeConstParser, UnsafeSpecializationMarkerParser, }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; @@ -178,6 +178,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 5c748e956a06..b9d387e072c9 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -299,6 +299,7 @@ pub fn check_builtin_meta_item( | sym::align | sym::deprecated | sym::optimize + | sym::pointee | sym::cold | sym::target_feature | sym::rustc_allow_const_fn_unstable diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 820255afe274..2009ddc1e2d5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -251,6 +251,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) + | AttributeKind::Pointee(..) | AttributeKind::Dummy | AttributeKind::OmitGdbPrettyPrinterSection, ) => { /* do nothing */ } @@ -381,7 +382,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfg_attr_trace // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) - | sym::pointee // FIXME(derive_coerce_pointee) | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) From 02dc14b25c729b8167620d2c2381ebbab20a0a04 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 14 Jul 2025 16:28:32 -0700 Subject: [PATCH 42/64] Update mdbook to 0.4.52 Changelog: https://github.com/rust-lang/mdBook/blob/master/CHANGELOG.md#mdbook-0452 This primarily picks up a few fixes. --- src/tools/rustbook/Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 050ddf47baef..27798d6aeb0b 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -885,9 +885,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.51" +version = "0.4.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328" +checksum = "93c284d2855916af7c5919cf9ad897cfc77d3c2db6f55429c7cfb769182030ec" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 69c0cfaf5c99..c7c6e39f1577 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.51" +version = "0.4.52" default-features = false features = ["search"] From ed88af21637ff3677100fd26f8db354cd6134ad4 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Mon, 14 Jul 2025 04:28:20 +0800 Subject: [PATCH 43/64] Recover and suggest use `;` to construct array type Signed-off-by: xizheyin --- compiler/rustc_parse/src/parser/ty.rs | 59 +++++++++++++- src/tools/tidy/src/issues.txt | 1 - src/tools/tidy/src/ui_tests.rs | 2 +- tests/ui/issues/issue-50571.fixed | 10 --- tests/ui/issues/issue-50571.rs | 10 --- tests/ui/issues/issue-50571.stderr | 15 ---- tests/ui/parser/better-expected.rs | 2 +- tests/ui/parser/better-expected.stderr | 12 ++- .../issues/error-pattern-issue-50571.rs | 11 +++ .../issues/error-pattern-issue-50571.stderr | 28 +++++++ tests/ui/parser/recover/array-type-no-semi.rs | 11 ++- .../parser/recover/array-type-no-semi.stderr | 81 +++++++++++-------- .../removed-syntax-fixed-vec.rs | 7 +- .../removed-syntax-fixed-vec.stderr | 21 ++++- 14 files changed, 183 insertions(+), 87 deletions(-) delete mode 100644 tests/ui/issues/issue-50571.fixed delete mode 100644 tests/ui/issues/issue-50571.rs delete mode 100644 tests/ui/issues/issue-50571.stderr create mode 100644 tests/ui/parser/issues/error-pattern-issue-50571.rs create mode 100644 tests/ui/parser/issues/error-pattern-issue-50571.stderr diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a997be3405d6..740dd10ea8ba 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -575,14 +575,69 @@ impl<'a> Parser<'a> { self.expect(exp!(CloseBracket))?; } TyKind::Array(elt_ty, length) - } else { - self.expect(exp!(CloseBracket))?; + } else if self.eat(exp!(CloseBracket)) { TyKind::Slice(elt_ty) + } else { + self.maybe_recover_array_ty_without_semi(elt_ty)? }; Ok(ty) } + /// Recover from malformed array type syntax. + /// + /// This method attempts to recover from cases like: + /// - `[u8, 5]` → suggests using `;`, return a Array type + /// - `[u8 5]` → suggests using `;`, return a Array type + /// Consider to add more cases in the future. + fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: P) -> PResult<'a, TyKind> { + let span = self.token.span; + let token_descr = super::token_descr(&self.token); + let mut err = + self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr)); + err.span_label(span, "expected `;` or `]`"); + err.note("you might have meant to write a slice or array type"); + + // If we cannot recover, return the error immediately. + if !self.may_recover() { + return Err(err); + } + + let snapshot = self.create_snapshot_for_diagnostic(); + + let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) { + // Consume common erroneous separators. + self.prev_token.span + } else { + self.token.span.shrink_to_lo() + }; + + // we first try to parse pattern like `[u8 5]` + let length = match self.parse_expr_anon_const() { + Ok(length) => length, + Err(e) => { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + }; + + if let Err(e) = self.expect(exp!(CloseBracket)) { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + + err.span_suggestion_verbose( + suggestion_span, + "you might have meant to use `;` as the separator", + ";", + Applicability::MaybeIncorrect, + ); + err.emit(); + Ok(TyKind::Array(elt_ty, length)) + } + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let and_span = self.prev_token.span; let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime()); diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index cac4dba2b49d..8b57db23d01c 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2338,7 +2338,6 @@ ui/issues/issue-50415.rs ui/issues/issue-50442.rs ui/issues/issue-50471.rs ui/issues/issue-50518.rs -ui/issues/issue-50571.rs ui/issues/issue-50581.rs ui/issues/issue-50582.rs ui/issues/issue-50585.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 53226fcb80e6..74f8104c7e98 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1619; +const ISSUES_ENTRY_LIMIT: u32 = 1616; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed deleted file mode 100644 index 6d73f17cca4c..000000000000 --- a/tests/ui/issues/issue-50571.fixed +++ /dev/null @@ -1,10 +0,0 @@ -//@ edition: 2015 -//@ run-rustfix - -#![allow(dead_code)] -trait Foo { - fn foo(_: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies -} - -fn main() {} diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs deleted file mode 100644 index dd840ffe4d17..000000000000 --- a/tests/ui/issues/issue-50571.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ edition: 2015 -//@ run-rustfix - -#![allow(dead_code)] -trait Foo { - fn foo([a, b]: [i32; 2]) {} - //~^ ERROR: patterns aren't allowed in methods without bodies -} - -fn main() {} diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr deleted file mode 100644 index 9b00fe0f5db6..000000000000 --- a/tests/ui/issues/issue-50571.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/issue-50571.rs:6:12 - | -LL | fn foo([a, b]: [i32; 2]) {} - | ^^^^^^ - | -help: give this argument a name or use an underscore to ignore it - | -LL - fn foo([a, b]: [i32; 2]) {} -LL + fn foo(_: [i32; 2]) {} - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/parser/better-expected.rs b/tests/ui/parser/better-expected.rs index 16b61caa4dff..91128c39691d 100644 --- a/tests/ui/parser/better-expected.rs +++ b/tests/ui/parser/better-expected.rs @@ -1,3 +1,3 @@ fn main() { - let x: [isize 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` + let x: [isize 3]; //~ ERROR expected `;` or `]`, found `3` } diff --git a/tests/ui/parser/better-expected.stderr b/tests/ui/parser/better-expected.stderr index f4ec933be164..4646ce7eff0e 100644 --- a/tests/ui/parser/better-expected.stderr +++ b/tests/ui/parser/better-expected.stderr @@ -1,10 +1,14 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` +error: expected `;` or `]`, found `3` --> $DIR/better-expected.rs:2:19 | LL | let x: [isize 3]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `x` + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL | let x: [isize ;3]; + | + error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.rs b/tests/ui/parser/issues/error-pattern-issue-50571.rs new file mode 100644 index 000000000000..0c2ce6052cb8 --- /dev/null +++ b/tests/ui/parser/issues/error-pattern-issue-50571.rs @@ -0,0 +1,11 @@ +// There is a regression introduced for issue #143828 +//@ edition: 2015 + +#![allow(dead_code)] +trait Foo { + fn foo([a, b]: [i32; 2]) {} + //~^ ERROR: expected `;` or `]`, found `,` + //~| ERROR: patterns aren't allowed in methods without bodies +} + +fn main() {} diff --git a/tests/ui/parser/issues/error-pattern-issue-50571.stderr b/tests/ui/parser/issues/error-pattern-issue-50571.stderr new file mode 100644 index 000000000000..47457cff461c --- /dev/null +++ b/tests/ui/parser/issues/error-pattern-issue-50571.stderr @@ -0,0 +1,28 @@ +error: expected `;` or `]`, found `,` + --> $DIR/error-pattern-issue-50571.rs:6:14 + | +LL | fn foo([a, b]: [i32; 2]) {} + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - fn foo([a, b]: [i32; 2]) {} +LL + fn foo([a; b]: [i32; 2]) {} + | + +error[E0642]: patterns aren't allowed in methods without bodies + --> $DIR/error-pattern-issue-50571.rs:6:12 + | +LL | fn foo([a, b]: [i32; 2]) {} + | ^^^^^^ + | +help: give this argument a name or use an underscore to ignore it + | +LL - fn foo([a, b]: [i32; 2]) {} +LL + fn foo(_: [i32; 2]) {} + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0642`. diff --git a/tests/ui/parser/recover/array-type-no-semi.rs b/tests/ui/parser/recover/array-type-no-semi.rs index ae5efbaf36ca..2cc5d979604c 100644 --- a/tests/ui/parser/recover/array-type-no-semi.rs +++ b/tests/ui/parser/recover/array-type-no-semi.rs @@ -5,14 +5,13 @@ fn main() { let x = 5; let b: [i32, 5]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - //~| ERROR expected value, found builtin type `i32` [E0423] + //~^ ERROR expected `;` or `]`, found `,` let a: [i32, ]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` + //~^ ERROR expected `;` or `]`, found `,` //~| ERROR expected value, found builtin type `i32` [E0423] let c: [i32, x]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - //~| ERROR expected value, found builtin type `i32` [E0423] + //~^ ERROR expected `;` or `]`, found `,` + //~| ERROR attempt to use a non-constant value in a constant [E0435] let e: [i32 5]; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` + //~^ ERROR expected `;` or `]`, found `5` } diff --git a/tests/ui/parser/recover/array-type-no-semi.stderr b/tests/ui/parser/recover/array-type-no-semi.stderr index 84b7282b4fed..82330465144c 100644 --- a/tests/ui/parser/recover/array-type-no-semi.stderr +++ b/tests/ui/parser/recover/array-type-no-semi.stderr @@ -1,56 +1,71 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` +error: expected `;` or `]`, found `,` --> $DIR/array-type-no-semi.rs:7:16 | LL | let b: [i32, 5]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `b` - | help: use `=` if you meant to assign + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - let b: [i32, 5]; +LL + let b: [i32; 5]; + | -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - --> $DIR/array-type-no-semi.rs:10:16 +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi.rs:9:16 | LL | let a: [i32, ]; - | - ^ expected one of 7 possible tokens + | - ^ expected `;` or `]` | | | while parsing the type for `a` | help: use `=` if you meant to assign + | + = note: you might have meant to write a slice or array type -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `,` - --> $DIR/array-type-no-semi.rs:13:16 +error: expected `;` or `]`, found `,` + --> $DIR/array-type-no-semi.rs:12:16 | LL | let c: [i32, x]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `c` - | help: use `=` if you meant to assign + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - let c: [i32, x]; +LL + let c: [i32; x]; + | -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `5` - --> $DIR/array-type-no-semi.rs:16:17 +error: expected `;` or `]`, found `5` + --> $DIR/array-type-no-semi.rs:15:17 | LL | let e: [i32 5]; - | - ^ expected one of 7 possible tokens - | | - | while parsing the type for `e` - -error[E0423]: expected value, found builtin type `i32` - --> $DIR/array-type-no-semi.rs:7:13 + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL | let e: [i32 ;5]; + | + + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/array-type-no-semi.rs:12:18 + | +LL | let c: [i32, x]; + | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL - let x = 5; +LL + const x: /* Type */ = 5; | -LL | let b: [i32, 5]; - | ^^^ not a value error[E0423]: expected value, found builtin type `i32` - --> $DIR/array-type-no-semi.rs:10:13 + --> $DIR/array-type-no-semi.rs:9:13 | LL | let a: [i32, ]; | ^^^ not a value -error[E0423]: expected value, found builtin type `i32` - --> $DIR/array-type-no-semi.rs:13:13 - | -LL | let c: [i32, x]; - | ^^^ not a value +error: aborting due to 6 previous errors -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0423`. +Some errors have detailed explanations: E0423, E0435. +For more information about an error, try `rustc --explain E0423`. diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs index 560efecb91cf..fb9a1c643fcc 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.rs @@ -1 +1,6 @@ -type v = [isize * 3]; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` +type v = [isize * 3]; +//~^ ERROR expected `;` or `]`, found `*` +//~| WARN type `v` should have an upper camel case name [non_camel_case_types] + + +fn main() {} diff --git a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr index 5bc9c2ccf00a..8d7938a1a469 100644 --- a/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr +++ b/tests/ui/parser/removed-syntax/removed-syntax-fixed-vec.stderr @@ -1,8 +1,23 @@ -error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` +error: expected `;` or `]`, found `*` --> $DIR/removed-syntax-fixed-vec.rs:1:17 | LL | type v = [isize * 3]; - | ^ expected one of 7 possible tokens + | ^ expected `;` or `]` + | + = note: you might have meant to write a slice or array type +help: you might have meant to use `;` as the separator + | +LL - type v = [isize * 3]; +LL + type v = [isize ; 3]; + | -error: aborting due to 1 previous error +warning: type `v` should have an upper camel case name + --> $DIR/removed-syntax-fixed-vec.rs:1:6 + | +LL | type v = [isize * 3]; + | ^ help: convert the identifier to upper camel case (notice the capitalization): `V` + | + = note: `#[warn(non_camel_case_types)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted From a14baf1e56cf9049992c25e0abb9ee4a7242e057 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 7 Jul 2025 09:04:21 +0200 Subject: [PATCH 44/64] Define datastructures for `#[cfg]` attribute, move StrippedCfgItem --- compiler/rustc_ast/src/expand/mod.rs | 17 ------------ .../src/attributes.rs | 27 ++++++++++++++++++- compiler/rustc_expand/src/base.rs | 10 +++++-- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 3 +-- compiler/rustc_middle/src/ty/parameterized.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 17 +++++++++--- 10 files changed, 53 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_ast/src/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs index 323a8fab6d59..069bff67b97a 100644 --- a/compiler/rustc_ast/src/expand/mod.rs +++ b/compiler/rustc_ast/src/expand/mod.rs @@ -1,24 +1,7 @@ //! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`. use rustc_macros::{Decodable, Encodable, HashStable_Generic}; -use rustc_span::Ident; -use rustc_span::def_id::DefId; - -use crate::MetaItem; pub mod allocator; pub mod autodiff_attrs; pub mod typetree; - -#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] -pub struct StrippedCfgItem { - pub parent_module: ModId, - pub ident: Ident, - pub cfg: MetaItem, -} - -impl StrippedCfgItem { - pub fn map_mod_id(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem { - StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } - } -} diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9b14ed88978b..995ac514d8d6 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -3,7 +3,7 @@ use rustc_ast::token::CommentKind; use rustc_ast::{self as ast, AttrStyle}; use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::hygiene::Transparency; -use rustc_span::{Span, Symbol}; +use rustc_span::{Ident, Span, Symbol}; use thin_vec::ThinVec; use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; @@ -69,6 +69,7 @@ pub enum ReprAttr { ReprAlign(Align), } pub use ReprAttr::*; +use rustc_span::def_id::DefId; pub enum TransparencyError { UnknownTransparency(Symbol, Span), @@ -140,6 +141,30 @@ pub enum UsedBy { Linker, } +#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)] +pub struct StrippedCfgItem { + pub parent_module: ModId, + pub ident: Ident, + pub cfg: (CfgEntry, Span), +} + +impl StrippedCfgItem { + pub fn map_mod_id(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem { + StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg } + } +} + +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum CfgEntry { + All(ThinVec, Span), + Any(ThinVec, Span), + Not(Box, Span), + Bool(bool, Span), + NameValue { name: Symbol, name_span: Span, value: Option<(Symbol, Span)>, span: Span }, + Version(Option, Span), +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 757a7e1c8e77..ce3006c2604a 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -11,7 +11,7 @@ use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; -use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr}; +use rustc_attr_data_structures::{AttributeKind, CfgEntry, Deprecation, Stability, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; @@ -1128,7 +1128,13 @@ pub trait ResolverExpand { /// HIR proc macros items back to their harness items. fn declare_proc_macro(&mut self, id: NodeId); - fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem); + fn append_stripped_cfg_item( + &mut self, + parent_node: NodeId, + ident: Ident, + cfg: CfgEntry, + cfg_span: Span, + ); /// Tools registered with `#![register_tool]` and used by tool attributes and lints. fn registered_tools(&self) -> &RegisteredTools; diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8347626080e6..915c97316880 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -7,7 +7,7 @@ use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; -use rustc_ast::expand::StrippedCfgItem; +use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_hir::PreciseCapturingArgKind; diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index f140ab4755bd..43a7af9ce380 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -110,7 +110,7 @@ macro_rules! arena_types { [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, - [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, + [] stripped_cfg_items: rustc_attr_data_structures::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, [] features: rustc_feature::Features, [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 842d118449a5..935cc8895740 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -69,8 +69,8 @@ use std::sync::Arc; use rustc_abi::Align; use rustc_arena::TypedArena; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::allocator::AllocatorKind; +use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a352ab3fd08a..6e8f1e8fdd5b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -25,10 +25,9 @@ pub use generic_args::{GenericArgKind, TermKind, *}; pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; -use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_attr_data_structures::{AttributeKind, StrippedCfgItem, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 3d601fc05338..dbacbe21edb7 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -87,7 +87,7 @@ trivially_parameterized_over_tcx! { ty::IntrinsicDef, rustc_ast::Attribute, rustc_ast::DelimArgs, - rustc_ast::expand::StrippedCfgItem, + rustc_attr_data_structures::StrippedCfgItem, rustc_attr_data_structures::ConstStability, rustc_attr_data_structures::DefaultBodyStability, rustc_attr_data_structures::Deprecation, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f8d1b6783e39..c2b3451d4a1d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -36,12 +36,12 @@ use late::{ }; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, NodeId, Path, attr, }; +use rustc_attr_data_structures::StrippedCfgItem; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5864b035f73d..cbb24289f51f 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,10 +5,9 @@ use std::cell::Cell; use std::mem; use std::sync::Arc; -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::StabilityLevel; +use rustc_attr_data_structures::{CfgEntry, StabilityLevel, StrippedCfgItem}; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, @@ -485,8 +484,18 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { self.proc_macros.push(self.local_def_id(id)) } - fn append_stripped_cfg_item(&mut self, parent_node: NodeId, ident: Ident, cfg: ast::MetaItem) { - self.stripped_cfg_items.push(StrippedCfgItem { parent_module: parent_node, ident, cfg }); + fn append_stripped_cfg_item( + &mut self, + parent_node: NodeId, + ident: Ident, + cfg: CfgEntry, + cfg_span: Span, + ) { + self.stripped_cfg_items.push(StrippedCfgItem { + parent_module: parent_node, + ident, + cfg: (cfg, cfg_span), + }); } fn registered_tools(&self) -> &RegisteredTools { From 38dd6f5206dea1388755c48afe55ad5af5a12577 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 7 Jul 2025 09:06:44 +0200 Subject: [PATCH 45/64] Allow `Early` stage to emit errors --- compiler/rustc_ast_lowering/src/lib.rs | 9 +- compiler/rustc_attr_parsing/src/context.rs | 97 ++++++++++++++++--- .../src/deriving/generic/mod.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 1 + 5 files changed, 93 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 348fe2ee40aa..1c96a375035a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -42,7 +42,7 @@ use std::sync::Arc; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, *}; -use rustc_attr_parsing::{AttributeParser, OmitDoc}; +use rustc_attr_parsing::{AttributeParser, Late, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -192,7 +192,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), + attribute_parser: AttributeParser::new( + tcx.sess, + tcx.features(), + registered_tools, + Late, + ), delayed_lints: Vec::new(), } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6c70f2ee4ee0..1f6675b4c5a8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -1,6 +1,5 @@ use std::cell::RefCell; use std::collections::BTreeMap; -use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; @@ -202,7 +201,11 @@ pub trait Stage: Sized + 'static + Sealed { fn parsers() -> &'static group_type!(Self); - fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed; + fn emit_err<'sess>( + &self, + sess: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed; } // allow because it's a sealed trait @@ -214,8 +217,16 @@ impl Stage for Early { fn parsers() -> &'static group_type!(Self) { &early::ATTRIBUTE_PARSERS } - fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { - sess.dcx().create_err(diag).delay_as_bug() + fn emit_err<'sess>( + &self, + sess: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { + if self.emit_errors { + sess.dcx().emit_err(diag) + } else { + sess.dcx().create_err(diag).delay_as_bug() + } } } @@ -228,20 +239,29 @@ impl Stage for Late { fn parsers() -> &'static group_type!(Self) { &late::ATTRIBUTE_PARSERS } - fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + fn emit_err<'sess>( + &self, + tcx: &'sess Session, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { tcx.dcx().emit_err(diag) } } /// used when parsing attributes for miscellaneous things *before* ast lowering -pub struct Early; +pub struct Early { + /// Whether to emit errors or delay them as a bug + /// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed + /// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted + pub emit_errors: bool, +} /// used when parsing attributes during ast lowering pub struct Late; /// Context given to every attribute parser when accepting /// /// Gives [`AttributeParser`]s enough information to create errors, for example. -pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { +pub struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) shared: SharedContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, @@ -257,7 +277,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { - S::emit_err(&self.sess, diag) + self.stage.emit_err(&self.sess, diag) } /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing @@ -472,7 +492,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create /// errors, for example. -pub(crate) struct SharedContext<'p, 'sess, S: Stage> { +pub struct SharedContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. pub(crate) cx: &'p mut AttributeParser<'sess, S>, @@ -540,7 +560,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> { pub(crate) tools: Vec, features: Option<&'sess Features>, sess: &'sess Session, - stage: PhantomData, + stage: S, /// *Only* parse attributes with this symbol. /// @@ -569,13 +589,14 @@ impl<'sess> AttributeParser<'sess, Early> { sym: Symbol, target_span: Span, target_node_id: NodeId, + features: Option<&'sess Features>, ) -> Option { let mut p = Self { - features: None, + features, tools: Vec::new(), parse_only: Some(sym), sess, - stage: PhantomData, + stage: Early { emit_errors: false }, }; let mut parsed = p.parse_attribute_list( attrs, @@ -591,11 +612,55 @@ impl<'sess> AttributeParser<'sess, Early> { parsed.pop() } + + pub fn parse_single( + sess: &'sess Session, + attr: &ast::Attribute, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + emit_errors: bool, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T, + template: &AttributeTemplate, + ) -> T { + let mut parser = Self { + features, + tools: Vec::new(), + parse_only: None, + sess, + stage: Early { emit_errors }, + }; + let ast::AttrKind::Normal(normal_attr) = &attr.kind else { + panic!("parse_single called on a doc attr") + }; + let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx()); + let path = meta_parser.path(); + let args = meta_parser.args(); + let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { + shared: SharedContext { + cx: &mut parser, + target_span, + target_id: target_node_id, + emit_lint: &mut |_lint| { + panic!("can't emit lints here for now (nothing uses this atm)"); + }, + }, + attr_span: attr.span, + template, + attr_path: path.get_attribute_path(), + }; + parse_fn(&mut cx, args) + } } impl<'sess, S: Stage> AttributeParser<'sess, S> { - pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { - Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } + pub fn new( + sess: &'sess Session, + features: &'sess Features, + tools: Vec, + stage: S, + ) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage } } pub(crate) fn sess(&self) -> &'sess Session { @@ -606,6 +671,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { self.features.expect("features not available at this point in the compiler") } + pub(crate) fn features_option(&self) -> Option<&'sess Features> { + self.features + } + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { self.sess().dcx() } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 8c3093acea45..c55a9e73e382 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> { match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None), Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index bc9badbb232e..db89396d1dc2 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -167,7 +167,7 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, None), Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index e2caf632dd2d..781e2ce97040 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -132,6 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), + Early { emit_errors: false }, ); let attrs = parser.parse_attribute_list( &i.attrs, From 30f4a9cd539a9bffda21e056c8ab291d02e85541 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 7 Jul 2025 09:08:02 +0200 Subject: [PATCH 46/64] Move `cfg` -> `cfg_old` --- .../src/attributes/cfg_old.rs | 247 ++++++++++++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/lib.rs | 3 +- 3 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/cfg_old.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs new file mode 100644 index 000000000000..c5025a8b6eac --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/cfg_old.rs @@ -0,0 +1,247 @@ +use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; +use rustc_ast_pretty::pprust; +use rustc_attr_data_structures::RustcVersion; +use rustc_feature::{Features, GatedCfg, find_gated_cfg}; +use rustc_session::Session; +use rustc_session::config::ExpectedValues; +use rustc_session::lint::builtin::UNEXPECTED_CFGS; +use rustc_session::lint::{BuiltinLintDiag, Lint}; +use rustc_session::parse::feature_err; +use rustc_span::{Span, Symbol, sym}; + +use crate::session_diagnostics::{self, UnsupportedLiteralReason}; +use crate::{fluent_generated, parse_version}; + +/// Emitter of a builtin lint from `cfg_matches`. +/// +/// Used to support emitting a lint (currently on check-cfg), either: +/// - as an early buffered lint (in `rustc`) +/// - or has a "normal" lint from HIR (in `rustdoc`) +pub trait CfgMatchesLintEmitter { + fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag); +} + +impl CfgMatchesLintEmitter for NodeId { + fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) { + sess.psess.buffer_lint(lint, sp, *self, diag); + } +} + +#[derive(Clone, Debug)] +pub struct Condition { + pub name: Symbol, + pub name_span: Span, + pub value: Option, + pub value_span: Option, + pub span: Span, +} + +/// Tests if a cfg-pattern matches the cfg set +pub fn cfg_matches( + cfg: &MetaItemInner, + sess: &Session, + lint_emitter: impl CfgMatchesLintEmitter, + features: Option<&Features>, +) -> bool { + eval_condition(cfg, sess, features, &mut |cfg| { + try_gate_cfg(cfg.name, cfg.span, sess, features); + match sess.psess.check_config.expecteds.get(&cfg.name) { + Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => { + lint_emitter.emit_span_lint( + sess, + UNEXPECTED_CFGS, + cfg.span, + BuiltinLintDiag::UnexpectedCfgValue( + (cfg.name, cfg.name_span), + cfg.value.map(|v| (v, cfg.value_span.unwrap())), + ), + ); + } + None if sess.psess.check_config.exhaustive_names => { + lint_emitter.emit_span_lint( + sess, + UNEXPECTED_CFGS, + cfg.span, + BuiltinLintDiag::UnexpectedCfgName( + (cfg.name, cfg.name_span), + cfg.value.map(|v| (v, cfg.value_span.unwrap())), + ), + ); + } + _ => { /* not unexpected */ } + } + sess.psess.config.contains(&(cfg.name, cfg.value)) + }) +} + +pub fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { + let gate = find_gated_cfg(|sym| sym == name); + if let (Some(feats), Some(gated_cfg)) = (features, gate) { + gate_cfg(gated_cfg, span, sess, feats); + } +} + +#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable +fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { + let (cfg, feature, has_feature) = gated_cfg; + if !has_feature(features) && !cfg_span.allows_unstable(*feature) { + let explain = format!("`cfg({cfg})` is experimental and subject to change"); + feature_err(sess, *feature, cfg_span, explain).emit(); + } +} + +/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to +/// evaluate individual items. +pub fn eval_condition( + cfg: &MetaItemInner, + sess: &Session, + features: Option<&Features>, + eval: &mut impl FnMut(Condition) -> bool, +) -> bool { + let dcx = sess.dcx(); + + let cfg = match cfg { + MetaItemInner::MetaItem(meta_item) => meta_item, + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { + return *b; + } + _ => { + dcx.emit_err(session_diagnostics::UnsupportedLiteral { + span: cfg.span(), + reason: UnsupportedLiteralReason::CfgBoolean, + is_bytestr: false, + start_point_span: sess.source_map().start_point(cfg.span()), + }); + return false; + } + }; + + match &cfg.kind { + MetaItemKind::List(mis) if cfg.has_name(sym::version) => { + try_gate_cfg(sym::version, cfg.span, sess, features); + let (min_version, span) = match &mis[..] { + [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { + (sym, span) + } + [ + MetaItemInner::Lit(MetaItemLit { span, .. }) + | MetaItemInner::MetaItem(MetaItem { span, .. }), + ] => { + dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); + return false; + } + [..] => { + dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { + span: cfg.span, + }); + return false; + } + }; + let Some(min_version) = parse_version(*min_version) else { + dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span }); + return false; + }; + + // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details + if sess.psess.assume_incomplete_release { + RustcVersion::current_overridable() > min_version + } else { + RustcVersion::current_overridable() >= min_version + } + } + MetaItemKind::List(mis) => { + for mi in mis.iter() { + if mi.meta_item_or_bool().is_none() { + dcx.emit_err(session_diagnostics::UnsupportedLiteral { + span: mi.span(), + reason: UnsupportedLiteralReason::Generic, + is_bytestr: false, + start_point_span: sess.source_map().start_point(mi.span()), + }); + return false; + } + } + + // The unwraps below may look dangerous, but we've already asserted + // that they won't fail with the loop above. + match cfg.name() { + Some(sym::any) => mis + .iter() + // We don't use any() here, because we want to evaluate all cfg condition + // as eval_condition can (and does) extra checks + .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), + Some(sym::all) => mis + .iter() + // We don't use all() here, because we want to evaluate all cfg condition + // as eval_condition can (and does) extra checks + .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), + Some(sym::not) => { + let [mi] = mis.as_slice() else { + dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); + return false; + }; + + !eval_condition(mi, sess, features, eval) + } + Some(sym::target) => { + if let Some(features) = features + && !features.cfg_target_compact() + { + feature_err( + sess, + sym::cfg_target_compact, + cfg.span, + fluent_generated::attr_parsing_unstable_cfg_target_compact, + ) + .emit(); + } + + mis.iter().fold(true, |res, mi| { + let Some(mut mi) = mi.meta_item().cloned() else { + dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { + span: mi.span(), + }); + return false; + }; + + if let [seg, ..] = &mut mi.path.segments[..] { + seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); + } + + res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval) + }) + } + _ => { + dcx.emit_err(session_diagnostics::InvalidPredicate { + span: cfg.span, + predicate: pprust::path_to_string(&cfg.path), + }); + false + } + } + } + MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { + dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); + true + } + MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { + dcx.emit_err(session_diagnostics::UnsupportedLiteral { + span: lit.span, + reason: UnsupportedLiteralReason::CfgString, + is_bytestr: lit.kind.is_bytestr(), + start_point_span: sess.source_map().start_point(lit.span), + }); + true + } + MetaItemKind::Word | MetaItemKind::NameValue(..) => { + let ident = cfg.ident().expect("multi-segment cfg predicate"); + eval(Condition { + name: ident.name, + name_span: ident.span, + value: cfg.value_str(), + value_span: cfg.name_value_literal_span(), + span: cfg.span, + }) + } + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 68c716d1a99d..200f13819602 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -27,6 +27,7 @@ use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; pub(crate) mod cfg; +pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod deprecation; diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 47eeb63bad3d..2102a26108bc 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -90,7 +90,8 @@ mod lints; pub mod parser; mod session_diagnostics; -pub use attributes::cfg::*; +pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr}; +pub use attributes::cfg_old::*; pub use attributes::util::{ find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, }; From a74a28493a00900616d5e52cd85b8b6bae761935 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 15 Jul 2025 15:10:24 +0800 Subject: [PATCH 47/64] Add tests for UB check in `set_len`, `from_raw_parts_in`, `from_parts_in` Signed-off-by: xizheyin --- .../ui/precondition-checks/vec-from-parts.rs | 15 ++++++++++ .../precondition-checks/vec-from-raw-parts.rs | 29 +++++++++++++++++++ tests/ui/precondition-checks/vec-set-len.rs | 11 +++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/ui/precondition-checks/vec-from-parts.rs create mode 100644 tests/ui/precondition-checks/vec-from-raw-parts.rs create mode 100644 tests/ui/precondition-checks/vec-set-len.rs diff --git a/tests/ui/precondition-checks/vec-from-parts.rs b/tests/ui/precondition-checks/vec-from-parts.rs new file mode 100644 index 000000000000..0bafb5aa715e --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-parts.rs @@ -0,0 +1,15 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity +#![feature(allocator_api)] + +use std::ptr::NonNull; + +fn main() { + let ptr: NonNull = std::ptr::NonNull::dangling(); + // Test Vec::from_parts_in with length > capacity + unsafe { + let alloc = std::alloc::Global; + let _vec = Vec::from_parts_in(ptr, 10, 5, alloc); + } +} diff --git a/tests/ui/precondition-checks/vec-from-raw-parts.rs b/tests/ui/precondition-checks/vec-from-raw-parts.rs new file mode 100644 index 000000000000..884d34c0a564 --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-raw-parts.rs @@ -0,0 +1,29 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity +//@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts + +#![feature(allocator_api)] + +fn main() { + let ptr = std::ptr::null_mut::(); + // Test Vec::from_raw_parts with length > capacity + unsafe { + #[cfg(vec_from_raw_parts)] + let _vec = Vec::from_raw_parts(ptr, 10, 5); + } + + // Test Vec::from_raw_parts_in with length > capacity + unsafe { + let alloc = std::alloc::Global; + #[cfg(vec_from_raw_parts_in)] + let _vec = Vec::from_raw_parts_in(ptr, 10, 5, alloc); + } + + // Test String::from_raw_parts with length > capacity + // Because it calls Vec::from_raw_parts, it should also fail + unsafe { + #[cfg(string_from_raw_parts)] + let _vec = String::from_raw_parts(ptr, 10, 5); + } +} diff --git a/tests/ui/precondition-checks/vec-set-len.rs b/tests/ui/precondition-checks/vec-set-len.rs new file mode 100644 index 000000000000..0987e7fe0282 --- /dev/null +++ b/tests/ui/precondition-checks/vec-set-len.rs @@ -0,0 +1,11 @@ +//@ run-fail +//@ compile-flags: -Cdebug-assertions=yes +//@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity() + +fn main() { + let mut vec: Vec = Vec::with_capacity(5); + // Test set_len with length > capacity + unsafe { + vec.set_len(10); + } +} From 6133c676d7b5e025121c858c4e7942cce70adf27 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 7 Jul 2025 09:09:54 +0200 Subject: [PATCH 48/64] Define attribute parser & config evaluator --- .../rustc_attr_parsing/src/attributes/cfg.rs | 474 ++++++++++-------- compiler/rustc_expand/src/config.rs | 52 +- compiler/rustc_expand/src/expand.rs | 38 +- compiler/rustc_parse/src/validate_attr.rs | 14 +- compiler/rustc_resolve/src/diagnostics.rs | 21 +- 5 files changed, 330 insertions(+), 269 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index a8d9229cbc35..a56855b3bd3d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,247 +1,291 @@ -use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; -use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::RustcVersion; -use rustc_feature::{Features, GatedCfg, find_gated_cfg}; +use rustc_ast::{LitKind, NodeId}; +use rustc_attr_data_structures::{CfgEntry, RustcVersion}; +use rustc_feature::{AttributeTemplate, Features, template}; use rustc_session::Session; use rustc_session::config::ExpectedValues; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; -use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; -use crate::session_diagnostics::{self, UnsupportedLiteralReason}; -use crate::{fluent_generated, parse_version}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; +use crate::{ + CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, +}; -/// Emitter of a builtin lint from `cfg_matches`. -/// -/// Used to support emitting a lint (currently on check-cfg), either: -/// - as an early buffered lint (in `rustc`) -/// - or has a "normal" lint from HIR (in `rustdoc`) -pub trait CfgMatchesLintEmitter { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag); +pub const CFG_TEMPLATE: AttributeTemplate = template!(List: "predicate"); + +pub fn parse_cfg_attr<'c, S: Stage>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, +) -> Option { + let ArgParser::List(list) = args else { + cx.expected_list(cx.attr_span); + return None; + }; + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + parse_cfg_entry(cx, single) } -impl CfgMatchesLintEmitter for NodeId { - fn emit_span_lint(&self, sess: &Session, lint: &'static Lint, sp: Span, diag: BuiltinLintDiag) { - sess.psess.buffer_lint(lint, sp, *self, diag); - } -} - -#[derive(Clone, Debug)] -pub struct Condition { - pub name: Symbol, - pub name_span: Span, - pub value: Option, - pub value_span: Option, - pub span: Span, -} - -/// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches( - cfg: &MetaItemInner, - sess: &Session, - lint_emitter: impl CfgMatchesLintEmitter, - features: Option<&Features>, -) -> bool { - eval_condition(cfg, sess, features, &mut |cfg| { - try_gate_cfg(cfg.name, cfg.span, sess, features); - match sess.psess.check_config.expecteds.get(&cfg.name) { - Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => { - lint_emitter.emit_span_lint( - sess, - UNEXPECTED_CFGS, - cfg.span, - BuiltinLintDiag::UnexpectedCfgValue( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), - ); +fn parse_cfg_entry( + cx: &mut AcceptContext<'_, '_, S>, + item: &MetaItemOrLitParser<'_>, +) -> Option { + Some(match item { + MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() { + ArgParser::List(list) => match meta.path().word_sym() { + Some(sym::not) => { + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span) + } + Some(sym::any) => CfgEntry::Any( + list.mixed().flat_map(|sub_item| parse_cfg_entry(cx, sub_item)).collect(), + list.span, + ), + Some(sym::all) => CfgEntry::All( + list.mixed().flat_map(|sub_item| parse_cfg_entry(cx, sub_item)).collect(), + list.span, + ), + Some(sym::target) => parse_cfg_entry_target(cx, list, meta.span())?, + Some(sym::version) => parse_cfg_entry_version(cx, list, meta.span())?, + _ => { + cx.emit_err(session_diagnostics::InvalidPredicate { + span: meta.span(), + predicate: meta.path().to_string(), + }); + return None; + } + }, + a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => { + let Some(name) = meta.path().word_sym() else { + cx.emit_err(session_diagnostics::CfgPredicateIdentifier { + span: meta.path().span(), + }); + return None; + }; + parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)? } - None if sess.psess.check_config.exhaustive_names => { - lint_emitter.emit_span_lint( - sess, - UNEXPECTED_CFGS, - cfg.span, - BuiltinLintDiag::UnexpectedCfgName( - (cfg.name, cfg.name_span), - cfg.value.map(|v| (v, cfg.value_span.unwrap())), - ), - ); + }, + MetaItemOrLitParser::Lit(lit) => match lit.kind { + LitKind::Bool(b) => CfgEntry::Bool(b, lit.span), + _ => { + cx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: lit.span }); + return None; } - _ => { /* not unexpected */ } - } - sess.psess.config.contains(&(cfg.name, cfg.value)) + }, + MetaItemOrLitParser::Err(_, _) => return None, }) } -fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| sym == name); - if let (Some(feats), Some(gated_cfg)) = (features, gate) { - gate_cfg(gated_cfg, span, sess, feats); - } +fn parse_cfg_entry_version( + cx: &mut AcceptContext<'_, '_, S>, + list: &MetaItemListParser<'_>, + meta_span: Span, +) -> Option { + try_gate_cfg(sym::version, meta_span, cx.sess(), Some(cx.features())); + let Some(version) = list.single() else { + cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span }); + return None; + }; + let Some(version_lit) = version.lit() else { + cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version.span() }); + return None; + }; + let Some(version_str) = version_lit.value_str() else { + cx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: version_lit.span }); + return None; + }; + + let min_version = parse_version(version_str).or_else(|| { + cx.sess() + .dcx() + .emit_warn(session_diagnostics::UnknownVersionLiteral { span: version_lit.span }); + None + }); + + Some(CfgEntry::Version(min_version, list.span)) } -#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable -fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) { - let (cfg, feature, has_feature) = gated_cfg; - if !has_feature(features) && !cfg_span.allows_unstable(*feature) { - let explain = format!("`cfg({cfg})` is experimental and subject to change"); - feature_err(sess, *feature, cfg_span, explain).emit(); +fn parse_cfg_entry_target( + cx: &mut AcceptContext<'_, '_, S>, + list: &MetaItemListParser<'_>, + meta_span: Span, +) -> Option { + if !cx.features().cfg_target_compact() { + feature_err( + cx.sess(), + sym::cfg_target_compact, + meta_span, + fluent_generated::attr_parsing_unstable_cfg_target_compact, + ) + .emit(); } -} -/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to -/// evaluate individual items. -pub fn eval_condition( - cfg: &MetaItemInner, - sess: &Session, - features: Option<&Features>, - eval: &mut impl FnMut(Condition) -> bool, -) -> bool { - let dcx = sess.dcx(); + let mut result = ThinVec::new(); + for sub_item in list.mixed() { + // First, validate that this is a NameValue item + let Some(sub_item) = sub_item.meta_item() else { + cx.expected_name_value(sub_item.span(), None); + continue; + }; + let Some(nv) = sub_item.args().name_value() else { + cx.expected_name_value(sub_item.span(), None); + continue; + }; - let cfg = match cfg { - MetaItemInner::MetaItem(meta_item) => meta_item, - MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { - return *b; - } - _ => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: cfg.span(), - reason: UnsupportedLiteralReason::CfgBoolean, - is_bytestr: false, - start_point_span: sess.source_map().start_point(cfg.span()), + // Then, parse it as a name-value item + let Some(name) = sub_item.path().word_sym() else { + cx.emit_err(session_diagnostics::CfgPredicateIdentifier { + span: sub_item.path().span(), }); - return false; + return None; + }; + let name = Symbol::intern(&format!("target_{name}")); + if let Some(cfg) = + parse_name_value(name, sub_item.path().span(), Some(nv), sub_item.span(), cx) + { + result.push(cfg); + } + } + Some(CfgEntry::All(result, list.span)) +} + +fn parse_name_value( + name: Symbol, + name_span: Span, + value: Option<&NameValueParser>, + span: Span, + cx: &mut AcceptContext<'_, '_, S>, +) -> Option { + try_gate_cfg(name, span, cx.sess(), cx.features_option()); + + let value = match value { + None => None, + Some(value) => { + let Some(value_str) = value.value_as_str() else { + cx.expected_string_literal(value.value_span, Some(value.value_as_lit())); + return None; + }; + Some((value_str, value.value_span)) } }; - match &cfg.kind { - MetaItemKind::List(mis) if cfg.has_name(sym::version) => { - try_gate_cfg(sym::version, cfg.span, sess, features); - let (min_version, span) = match &mis[..] { - [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { - (sym, span) - } - [ - MetaItemInner::Lit(MetaItemLit { span, .. }) - | MetaItemInner::MetaItem(MetaItem { span, .. }), - ] => { - dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span }); - return false; - } - [..] => { - dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { - span: cfg.span, - }); - return false; - } - }; - let Some(min_version) = parse_version(*min_version) else { - dcx.emit_warn(session_diagnostics::UnknownVersionLiteral { span: *span }); - return false; - }; + Some(CfgEntry::NameValue { name, name_span, value, span }) +} - // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details - if sess.psess.assume_incomplete_release { - RustcVersion::current_overridable() > min_version - } else { - RustcVersion::current_overridable() >= min_version - } - } - MetaItemKind::List(mis) => { - for mi in mis.iter() { - if mi.meta_item_or_bool().is_none() { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: mi.span(), - reason: UnsupportedLiteralReason::Generic, - is_bytestr: false, - start_point_span: sess.source_map().start_point(mi.span()), - }); - return false; +pub fn eval_config_entry( + sess: &Session, + cfg_entry: &CfgEntry, + id: NodeId, + features: Option<&Features>, +) -> EvalConfigResult { + match cfg_entry { + CfgEntry::All(subs, ..) => { + let mut all = None; + for sub in subs { + let res = eval_config_entry(sess, sub, id, features); + // We cannot short-circuit because `eval_config_entry` emits some lints + if !res.as_bool() { + all.get_or_insert(res); } } - - // The unwraps below may look dangerous, but we've already asserted - // that they won't fail with the loop above. - match cfg.name() { - Some(sym::any) => mis - .iter() - // We don't use any() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), - Some(sym::all) => mis - .iter() - // We don't use all() here, because we want to evaluate all cfg condition - // as eval_condition can (and does) extra checks - .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), - Some(sym::not) => { - let [mi] = mis.as_slice() else { - dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); - return false; - }; - - !eval_condition(mi, sess, features, eval) - } - Some(sym::target) => { - if let Some(features) = features - && !features.cfg_target_compact() - { - feature_err( - sess, - sym::cfg_target_compact, - cfg.span, - fluent_generated::attr_parsing_unstable_cfg_target_compact, - ) - .emit(); - } - - mis.iter().fold(true, |res, mi| { - let Some(mut mi) = mi.meta_item().cloned() else { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { - span: mi.span(), - }); - return false; - }; - - if let [seg, ..] = &mut mi.path.segments[..] { - seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); - } - - res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval) - }) - } - _ => { - dcx.emit_err(session_diagnostics::InvalidPredicate { - span: cfg.span, - predicate: pprust::path_to_string(&cfg.path), - }); - false + all.unwrap_or_else(|| EvalConfigResult::True) + } + CfgEntry::Any(subs, span) => { + let mut any = None; + for sub in subs { + let res = eval_config_entry(sess, sub, id, features); + // We cannot short-circuit because `eval_config_entry` emits some lints + if res.as_bool() { + any.get_or_insert(res); } } - } - MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { - dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); - true - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - dcx.emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::CfgString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: sess.source_map().start_point(lit.span), - }); - true - } - MetaItemKind::Word | MetaItemKind::NameValue(..) => { - let ident = cfg.ident().expect("multi-segment cfg predicate"); - eval(Condition { - name: ident.name, - name_span: ident.span, - value: cfg.value_str(), - value_span: cfg.name_value_literal_span(), - span: cfg.span, + any.unwrap_or_else(|| EvalConfigResult::False { + reason: cfg_entry.clone(), + reason_span: *span, }) } + CfgEntry::Not(sub, span) => { + if eval_config_entry(sess, sub, id, features).as_bool() { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } + } else { + EvalConfigResult::True + } + } + CfgEntry::Bool(b, span) => { + if *b { + EvalConfigResult::True + } else { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } + } + } + CfgEntry::NameValue { name, name_span, value, span } => { + match sess.psess.check_config.expecteds.get(name) { + Some(ExpectedValues::Some(values)) if !values.contains(&value.map(|(v, _)| v)) => { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgValue((*name, *name_span), *value), + ); + } + None if sess.psess.check_config.exhaustive_names => { + id.emit_span_lint( + sess, + UNEXPECTED_CFGS, + *span, + BuiltinLintDiag::UnexpectedCfgName((*name, *name_span), *value), + ); + } + _ => { /* not unexpected */ } + } + + if sess.psess.config.contains(&(*name, value.map(|(v, _)| v))) { + EvalConfigResult::True + } else { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *span } + } + } + CfgEntry::Version(min_version, version_span) => { + let Some(min_version) = min_version else { + return EvalConfigResult::False { + reason: cfg_entry.clone(), + reason_span: *version_span, + }; + }; + // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details + let min_version_ok = if sess.psess.assume_incomplete_release { + RustcVersion::current_overridable() > *min_version + } else { + RustcVersion::current_overridable() >= *min_version + }; + if min_version_ok { + EvalConfigResult::True + } else { + EvalConfigResult::False { reason: cfg_entry.clone(), reason_span: *version_span } + } + } + } +} + +pub enum EvalConfigResult { + True, + False { reason: CfgEntry, reason_span: Span }, +} + +impl EvalConfigResult { + pub fn as_bool(&self) -> bool { + match self { + EvalConfigResult::True => true, + EvalConfigResult::False { .. } => false, + } } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 170ac39d1ec3..6922ddfd6bdd 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -11,6 +11,9 @@ use rustc_ast::{ NodeId, NormalAttr, }; use rustc_attr_parsing as attr; +use rustc_attr_parsing::{ + AttributeParser, CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr, +}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features, @@ -18,6 +21,7 @@ use rustc_feature::{ }; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; +use rustc_parse::validate_attr::deny_builtin_meta_unsafety; use rustc_session::Session; use rustc_session::parse::feature_err; use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; @@ -161,7 +165,10 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec attrs .iter() .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)) - .take_while(|attr| !is_cfg(attr) || strip_unconfigured.cfg_true(attr).0) + .take_while(|attr| { + !is_cfg(attr) + || strip_unconfigured.cfg_true(attr, strip_unconfigured.lint_node_id).as_bool() + }) .collect() } @@ -394,26 +401,42 @@ impl<'a> StripUnconfigured<'a> { /// Determines if a node with the given attributes should be included in this configuration. fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr).0) + attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr, self.lint_node_id).as_bool()) } - pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option) { - let meta_item = match validate_attr::parse_meta(&self.sess.psess, attr) { - Ok(meta_item) => meta_item, + pub(crate) fn cfg_true(&self, attr: &Attribute, node: NodeId) -> EvalConfigResult { + // We need to run this to do basic validation of the attribute, such as that lits are valid, etc + // FIXME(jdonszelmann) this should not be necessary in the future + match validate_attr::parse_meta(&self.sess.psess, attr) { + Ok(_) => {} Err(err) => { err.emit(); - return (true, None); + return EvalConfigResult::True; } + } + + // Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check + deny_builtin_meta_unsafety( + self.sess.dcx(), + attr.get_normal_item().unsafety, + &rustc_ast::Path::from_ident(attr.ident().unwrap()), + ); + + let Some(cfg) = AttributeParser::parse_single( + self.sess, + attr, + attr.span, + node, + self.features, + true, + parse_cfg_attr, + &CFG_TEMPLATE, + ) else { + // Cfg attribute was not parsable, give up + return EvalConfigResult::True; }; - validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item); - - ( - parse_cfg(&meta_item, self.sess).is_none_or(|meta_item| { - attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features) - }), - Some(meta_item), - ) + eval_config_entry(self.sess, &cfg, self.lint_node_id, self.features) } /// If attributes are not allowed on expressions, emit an error for `attr` @@ -465,6 +488,7 @@ impl<'a> StripUnconfigured<'a> { } } +/// FIXME: Still used by Rustdoc, should be removed after pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> { let span = meta_item.span; match meta_item.meta_item_list() { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 2de09aa1a280..f99060e9a216 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,6 +13,7 @@ use rustc_ast::{ MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; +use rustc_attr_parsing::EvalConfigResult; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::PResult; use rustc_feature::Features; @@ -2166,19 +2167,19 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn expand_cfg_true( &mut self, - node: &mut impl HasAttrs, + node: &mut (impl HasAttrs + HasNodeId), attr: ast::Attribute, pos: usize, - ) -> (bool, Option) { - let (res, meta_item) = self.cfg().cfg_true(&attr); - if res { + ) -> EvalConfigResult { + let res = self.cfg().cfg_true(&attr, node.node_id()); + if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. let trace_attr = attr_into_trace(attr, sym::cfg_trace); node.visit_attrs(|attrs| attrs.insert(pos, trace_attr)); } - (res, meta_item) + res } fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) { @@ -2199,20 +2200,21 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { return match self.take_first_attr(&mut node) { Some((attr, pos, derives)) => match attr.name() { Some(sym::cfg) => { - let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos); - if res { - continue; - } - - if let Some(meta_item) = meta_item { - for ident in node.declared_idents() { - self.cx.resolver.append_stripped_cfg_item( - self.cx.current_expansion.lint_node_id, - ident, - meta_item.clone(), - ) + let res = self.expand_cfg_true(&mut node, attr, pos); + match res { + EvalConfigResult::True => continue, + EvalConfigResult::False { reason, reason_span } => { + for ident in node.declared_idents() { + self.cx.resolver.append_stripped_cfg_item( + self.cx.current_expansion.lint_node_id, + ident, + reason.clone(), + reason_span, + ) + } } } + Default::default() } Some(sym::cfg_attr) => { @@ -2291,7 +2293,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { Some((attr, pos, derives)) => match attr.name() { Some(sym::cfg) => { let span = attr.span; - if self.expand_cfg_true(node, attr, pos).0 { + if self.expand_cfg_true(node, attr, pos).as_bool() { continue; } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 5c748e956a06..e000d61083dd 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -4,9 +4,9 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, - Safety, + Path, Safety, }; -use rustc_errors::{Applicability, FatalError, PResult}; +use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; @@ -247,14 +247,12 @@ pub fn check_attribute_safety( // Called by `check_builtin_meta_item` and code that manually denies // `unsafe(...)` in `cfg` -pub fn deny_builtin_meta_unsafety(psess: &ParseSess, meta: &MetaItem) { +pub fn deny_builtin_meta_unsafety(diag: DiagCtxtHandle<'_>, unsafety: Safety, name: &Path) { // This only supports denying unsafety right now - making builtin attributes // support unsafety will requite us to thread the actual `Attribute` through // for the nice diagnostics. - if let Safety::Unsafe(unsafe_span) = meta.unsafety { - psess - .dcx() - .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() }); + if let Safety::Unsafe(unsafe_span) = unsafety { + diag.emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: name.clone() }); } } @@ -326,7 +324,7 @@ pub fn check_builtin_meta_item( } if deny_unsafety { - deny_builtin_meta_unsafety(psess, meta); + deny_builtin_meta_unsafety(psess.dcx(), meta.unsafety, &meta.path); } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index b2f16fb1dfba..93d848787ef4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,11 +1,10 @@ -use rustc_ast::expand::StrippedCfgItem; use rustc_ast::ptr::P; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{ - self as ast, CRATE_NODE_ID, Crate, ItemKind, MetaItemInner, MetaItemKind, ModKind, NodeId, Path, -}; +use rustc_ast::{self as ast, CRATE_NODE_ID, Crate, ItemKind, ModKind, NodeId, Path}; use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{self as attr, AttributeKind, Stability, find_attr}; +use rustc_attr_data_structures::{ + self as attr, AttributeKind, CfgEntry, Stability, StrippedCfgItem, find_attr, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; @@ -2860,17 +2859,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let note = errors::FoundItemConfigureOut { span: ident.span }; err.subdiagnostic(note); - if let MetaItemKind::List(nested) = &cfg.kind - && let MetaItemInner::MetaItem(meta_item) = &nested[0] - && let MetaItemKind::NameValue(feature_name) = &meta_item.kind - { - let note = errors::ItemWasBehindFeature { - feature: feature_name.symbol, - span: meta_item.span, - }; + if let CfgEntry::NameValue { value: Some((feature, _)), .. } = cfg.0 { + let note = errors::ItemWasBehindFeature { feature, span: cfg.1 }; err.subdiagnostic(note); } else { - let note = errors::ItemWasCfgOut { span: cfg.span }; + let note = errors::ItemWasCfgOut { span: cfg.1 }; err.subdiagnostic(note); } } From c7f5ddc09871dc74c9f451435b042707eef5dc6c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 7 Jul 2025 09:10:38 +0200 Subject: [PATCH 49/64] Changes to diagnostics --- .../src/session_diagnostics.rs | 8 ++- tests/ui/attributes/malformed-attrs.rs | 2 +- tests/ui/attributes/malformed-attrs.stderr | 7 ++- tests/ui/cfg/cfg-target-compact-errors.rs | 12 ++-- tests/ui/cfg/cfg-target-compact-errors.stderr | 47 +++++++++----- tests/ui/cfg/cfg-version/syntax.stderr | 4 +- tests/ui/cfg/diagnostics-cross-crate.stderr | 12 ++-- tests/ui/cfg/diagnostics-reexport-2.stderr | 20 +++--- tests/ui/cfg/diagnostics-reexport.stderr | 16 ++--- tests/ui/cfg/diagnostics-same-crate.stderr | 16 ++--- tests/ui/check-cfg/compact-names.rs | 4 ++ tests/ui/check-cfg/compact-names.stderr | 11 +++- .../cfg-attr-syntax-validation.rs | 25 +++++--- .../cfg-attr-syntax-validation.stderr | 63 ++++++++++++------- tests/ui/macros/macro-outer-attributes.stderr | 12 +--- 15 files changed, 162 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 8a240639d75a..97bf3d1c5495 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -593,7 +593,13 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.code(E0565); } AttributeParseErrorReason::ExpectedNameValue(None) => { - // The suggestion we add below this match already contains enough information + // If the span is the entire attribute, the suggestion we add below this match already contains enough information + if self.span != self.attr_span { + diag.span_label( + self.span, + format!("expected this to be of the form `... = \"...\"`"), + ); + } } AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { diag.span_label( diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index aa52de63a609..5026687b97b0 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -100,7 +100,7 @@ //~^ ERROR malformed //~| ERROR the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type #[cfg] -//~^ ERROR is not followed by parentheses +//~^ ERROR malformed #[cfg_attr] //~^ ERROR malformed #[instruction_set] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 3dc3c32c936b..56f2be353e76 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,8 +1,11 @@ -error: `cfg` is not followed by parentheses +error[E0539]: malformed `cfg` attribute input --> $DIR/malformed-attrs.rs:102:1 | LL | #[cfg] - | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg(predicate)]` error: malformed `cfg_attr` attribute input --> $DIR/malformed-attrs.rs:104:1 diff --git a/tests/ui/cfg/cfg-target-compact-errors.rs b/tests/ui/cfg/cfg-target-compact-errors.rs index e00d42fe4d96..cfb19c58a197 100644 --- a/tests/ui/cfg/cfg-target-compact-errors.rs +++ b/tests/ui/cfg/cfg-target-compact-errors.rs @@ -3,19 +3,23 @@ #![feature(cfg_target_compact)] #[cfg(target(o::o))] -//~^ ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input fn one() {} #[cfg(target(os = 8))] -//~^ ERROR literal in `cfg` predicate value must be a string +//~^ ERROR malformed `cfg` attribute input fn two() {} #[cfg(target(os = "linux", pointer(width = "64")))] -//~^ ERROR invalid predicate `target_pointer` +//~^ ERROR malformed `cfg` attribute input fn three() {} #[cfg(target(true))] -//~^ ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input fn four() {} +#[cfg(target(clippy::os = "linux"))] +//~^ ERROR `cfg` predicate key must be an identifier +fn five() {} + fn main() {} diff --git a/tests/ui/cfg/cfg-target-compact-errors.stderr b/tests/ui/cfg/cfg-target-compact-errors.stderr index 219d9732c32b..7df6729e8812 100644 --- a/tests/ui/cfg/cfg-target-compact-errors.stderr +++ b/tests/ui/cfg/cfg-target-compact-errors.stderr @@ -1,28 +1,45 @@ -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-target-compact-errors.rs:5:14 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:5:1 | LL | #[cfg(target(o::o))] - | ^^^^ + | ^^^^^^^^^^^^^----^^^ + | | | + | | expected this to be of the form `... = "..."` + | help: must be of the form: `#[cfg(predicate)]` -error[E0565]: literal in `cfg` predicate value must be a string - --> $DIR/cfg-target-compact-errors.rs:9:19 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:9:1 | LL | #[cfg(target(os = 8))] - | ^ + | ^^^^^^^^^^^^^^^^^^-^^^ + | | | + | | expected a string literal here + | help: must be of the form: `#[cfg(predicate)]` -error[E0537]: invalid predicate `target_pointer` - --> $DIR/cfg-target-compact-errors.rs:13:28 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:13:1 | LL | #[cfg(target(os = "linux", pointer(width = "64")))] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------^^^ + | | | + | | expected this to be of the form `... = "..."` + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-target-compact-errors.rs:17:14 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:17:1 | LL | #[cfg(target(true))] - | ^^^^ + | ^^^^^^^^^^^^^----^^^ + | | | + | | expected this to be of the form `... = "..."` + | help: must be of the form: `#[cfg(predicate)]` -error: aborting due to 4 previous errors +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-target-compact-errors.rs:21:14 + | +LL | #[cfg(target(clippy::os = "linux"))] + | ^^^^^^^^^^ -Some errors have detailed explanations: E0537, E0565. -For more information about an error, try `rustc --explain E0537`. +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/cfg/cfg-version/syntax.stderr b/tests/ui/cfg/cfg-version/syntax.stderr index 2facd9607631..188f6d7aa5dc 100644 --- a/tests/ui/cfg/cfg-version/syntax.stderr +++ b/tests/ui/cfg/cfg-version/syntax.stderr @@ -17,10 +17,10 @@ LL | #[cfg(version(false))] | ^^^^^ error: expected single version literal - --> $DIR/syntax.rs:23:7 + --> $DIR/syntax.rs:23:14 | LL | #[cfg(version("1.43", "1.44", "1.45"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unknown version literal format, assuming it refers to a future version --> $DIR/syntax.rs:51:15 diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr index 3e32a856e954..155b3db2f429 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.stderr +++ b/tests/ui/cfg/diagnostics-cross-crate.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/auxiliary/cfged_out.rs:5:5 + --> $DIR/auxiliary/cfged_out.rs:5:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `uwu` in crate `cfged_out` --> $DIR/diagnostics-cross-crate.rs:7:16 @@ -33,10 +33,10 @@ note: found an item that was configured out LL | pub fn uwu() {} | ^^^ note: the item is gated here - --> $DIR/auxiliary/cfged_out.rs:2:5 + --> $DIR/auxiliary/cfged_out.rs:2:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `meow` in module `cfged_out::inner::right` --> $DIR/diagnostics-cross-crate.rs:24:30 @@ -67,10 +67,10 @@ note: found an item that was configured out LL | pub fn vanished() {} | ^^^^^^^^ note: the item is gated here - --> $DIR/auxiliary/cfged_out.rs:21:1 + --> $DIR/auxiliary/cfged_out.rs:21:7 | LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/cfg/diagnostics-reexport-2.stderr b/tests/ui/cfg/diagnostics-reexport-2.stderr index 95ac5a19b0b9..e1f91fcc5d10 100644 --- a/tests/ui/cfg/diagnostics-reexport-2.stderr +++ b/tests/ui/cfg/diagnostics-reexport-2.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport2` --> $DIR/diagnostics-reexport-2.rs:46:16 @@ -27,10 +27,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport30` --> $DIR/diagnostics-reexport-2.rs:50:17 @@ -44,10 +44,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport31` --> $DIR/diagnostics-reexport-2.rs:54:17 @@ -61,10 +61,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `gated` in `reexport32` --> $DIR/diagnostics-reexport-2.rs:58:17 @@ -78,10 +78,10 @@ note: found an item that was configured out LL | pub mod gated { | ^^^^^ note: the item is gated here - --> $DIR/diagnostics-reexport-2.rs:4:5 + --> $DIR/diagnostics-reexport-2.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr index 95dc4fac945e..bf1bbcba7e4c 100644 --- a/tests/ui/cfg/diagnostics-reexport.stderr +++ b/tests/ui/cfg/diagnostics-reexport.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub fn x() {} | ^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:17:5 + --> $DIR/diagnostics-reexport.rs:17:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0432]: unresolved imports `b::x`, `b::y` --> $DIR/diagnostics-reexport.rs:22:13 @@ -29,20 +29,20 @@ note: found an item that was configured out LL | pub fn x() {} | ^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:28:5 + --> $DIR/diagnostics-reexport.rs:28:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ note: found an item that was configured out --> $DIR/diagnostics-reexport.rs:32:12 | LL | pub fn y() {} | ^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:31:5 + --> $DIR/diagnostics-reexport.rs:31:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `uwu` in module `inner` --> $DIR/diagnostics-reexport.rs:38:12 @@ -56,10 +56,10 @@ note: found an item that was configured out LL | pub use super::uwu; | ^^^ note: the item is gated here - --> $DIR/diagnostics-reexport.rs:7:5 + --> $DIR/diagnostics-reexport.rs:7:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index 75a1bc39a013..121f25ca0906 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -10,10 +10,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:8:5 + --> $DIR/diagnostics-same-crate.rs:8:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0432]: unresolved import `super::inner::doesnt_exist` --> $DIR/diagnostics-same-crate.rs:35:23 @@ -27,10 +27,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:8:5 + --> $DIR/diagnostics-same-crate.rs:8:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` --> $DIR/diagnostics-same-crate.rs:54:12 @@ -44,10 +44,10 @@ note: found an item that was configured out LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:8:5 + --> $DIR/diagnostics-same-crate.rs:8:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `uwu` in module `inner` --> $DIR/diagnostics-same-crate.rs:49:12 @@ -61,10 +61,10 @@ note: found an item that was configured out LL | pub fn uwu() {} | ^^^ note: the item is gated here - --> $DIR/diagnostics-same-crate.rs:4:5 + --> $DIR/diagnostics-same-crate.rs:4:11 | LL | #[cfg(false)] - | ^^^^^^^^^^^^^ + | ^^^^^ error[E0425]: cannot find function `meow` in module `inner::right` --> $DIR/diagnostics-same-crate.rs:58:19 diff --git a/tests/ui/check-cfg/compact-names.rs b/tests/ui/check-cfg/compact-names.rs index 931afdf986f4..fbf8f9d20028 100644 --- a/tests/ui/check-cfg/compact-names.rs +++ b/tests/ui/check-cfg/compact-names.rs @@ -13,4 +13,8 @@ pub fn expected() {} //~^ WARNING unexpected `cfg` condition name pub fn unexpected() {} +#[cfg(target(os = "windows", architecture = "arm"))] +//~^ WARNING unexpected `cfg` condition name +pub fn unexpected2() {} + fn main() {} diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index 74ed0337e3b1..3221b4e07ec9 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -8,5 +8,14 @@ LL | #[cfg(target(os = "linux", architecture = "arm"))] = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default -warning: 1 warning emitted +warning: unexpected `cfg` condition name: `target_architecture` + --> $DIR/compact-names.rs:16:30 + | +LL | #[cfg(target(os = "windows", architecture = "arm"))] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))` + = note: see for more information about checking conditional configuration + +warning: 2 warnings emitted diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 47418b4e091b..df87a3d846ef 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -1,16 +1,24 @@ -#[cfg] //~ ERROR `cfg` is not followed by parentheses +#[cfg] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected this to be a list struct S1; -#[cfg = 10] //~ ERROR `cfg` is not followed by parentheses +#[cfg = 10] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected this to be a list struct S2; -#[cfg()] //~ ERROR `cfg` predicate is not specified +#[cfg()] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected a single argument here struct S3; -#[cfg(a, b)] //~ ERROR multiple `cfg` predicates are specified +#[cfg(a, b)] +//~^ ERROR malformed `cfg` attribute +//~| NOTE expected a single argument here struct S4; -#[cfg("str")] //~ ERROR `cfg` predicate key cannot be a literal +#[cfg("str")] //~ ERROR `cfg` predicate key must be an identifier struct S5; #[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier @@ -19,10 +27,12 @@ struct S6; #[cfg(a())] //~ ERROR invalid predicate `a` struct S7; -#[cfg(a = 10)] //~ ERROR literal in `cfg` predicate value must be a string +#[cfg(a = 10)] //~ ERROR malformed `cfg` attribute input +//~^ NOTE expected a string literal here struct S8; -#[cfg(a = b"hi")] //~ ERROR literal in `cfg` predicate value must be a string +#[cfg(a = b"hi")] //~ ERROR malformed `cfg` attribute input +//~^ NOTE expected a normal string literal, not a byte string literal struct S9; macro_rules! generate_s10 { @@ -34,5 +44,6 @@ macro_rules! generate_s10 { } generate_s10!(concat!("nonexistent")); +//~^ NOTE in this expansion of generate_s10! fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 66ce2ee98589..75e9b9209c08 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -1,61 +1,78 @@ -error: `cfg` is not followed by parentheses +error[E0539]: malformed `cfg` attribute input --> $DIR/cfg-attr-syntax-validation.rs:1:1 | LL | #[cfg] - | ^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` is not followed by parentheses - --> $DIR/cfg-attr-syntax-validation.rs:4:1 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:6:1 | LL | #[cfg = 10] - | ^^^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` predicate is not specified - --> $DIR/cfg-attr-syntax-validation.rs:7:1 +error[E0805]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:11:1 | LL | #[cfg()] - | ^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + | ^^^^^--^ + | | | + | | expected a single argument here + | help: must be of the form: `#[cfg(predicate)]` -error: multiple `cfg` predicates are specified - --> $DIR/cfg-attr-syntax-validation.rs:10:10 +error[E0805]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:16:1 | LL | #[cfg(a, b)] - | ^ + | ^^^^^------^ + | | | + | | expected a single argument here + | help: must be of the form: `#[cfg(predicate)]` -error: `cfg` predicate key cannot be a literal - --> $DIR/cfg-attr-syntax-validation.rs:13:7 +error: `cfg` predicate key must be an identifier + --> $DIR/cfg-attr-syntax-validation.rs:21:7 | LL | #[cfg("str")] | ^^^^^ error: `cfg` predicate key must be an identifier - --> $DIR/cfg-attr-syntax-validation.rs:16:7 + --> $DIR/cfg-attr-syntax-validation.rs:24:7 | LL | #[cfg(a::b)] | ^^^^ error[E0537]: invalid predicate `a` - --> $DIR/cfg-attr-syntax-validation.rs:19:7 + --> $DIR/cfg-attr-syntax-validation.rs:27:7 | LL | #[cfg(a())] | ^^^ -error[E0565]: literal in `cfg` predicate value must be a string - --> $DIR/cfg-attr-syntax-validation.rs:22:11 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:30:1 | LL | #[cfg(a = 10)] - | ^^ + | ^^^^^^^^^^--^^ + | | | + | | expected a string literal here + | help: must be of the form: `#[cfg(predicate)]` -error[E0565]: literal in `cfg` predicate value must be a string - --> $DIR/cfg-attr-syntax-validation.rs:25:11 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:34:1 | LL | #[cfg(a = b"hi")] - | -^^^^ + | ^^^^^^^^^^-^^^^^^ | | | help: consider removing the prefix + | + = note: expected a normal string literal, not a byte string literal error: expected unsuffixed literal, found `expr` metavariable - --> $DIR/cfg-attr-syntax-validation.rs:30:25 + --> $DIR/cfg-attr-syntax-validation.rs:40:25 | LL | #[cfg(feature = $expr)] | ^^^^^ @@ -67,5 +84,5 @@ LL | generate_s10!(concat!("nonexistent")); error: aborting due to 10 previous errors -Some errors have detailed explanations: E0537, E0565. +Some errors have detailed explanations: E0537, E0539, E0805. For more information about an error, try `rustc --explain E0537`. diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index a894c90f4c32..9215754d4bb1 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -10,16 +10,10 @@ note: found an item that was configured out LL | pub fn bar() { }); | ^^^ note: the item is gated here - --> $DIR/macro-outer-attributes.rs:5:45 + --> $DIR/macro-outer-attributes.rs:8:13 | -LL | $i:item) => (mod $nm { #[$a] $i }); } - | ^^^^^ -LL | -LL | / test!(a, -LL | | #[cfg(false)], -LL | | pub fn bar() { }); - | |_______________________- in this macro invocation - = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | #[cfg(false)], + | ^^^^^ help: consider importing this function | LL + use b::bar; From 7a7c74ad89df9f87824fa17fbbe0448d9ab6f7cc Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 7 Jul 2025 09:10:54 +0200 Subject: [PATCH 50/64] New example for E0536 --- .../rustc_error_codes/src/error_codes/E0536.md | 16 +++++++--------- tests/ui/span/E0536.rs | 7 +++---- tests/ui/span/E0536.stderr | 6 +++--- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md index c081a3d9cfa8..f00d17739448 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0536.md +++ b/compiler/rustc_error_codes/src/error_codes/E0536.md @@ -3,22 +3,20 @@ The `not` cfg-predicate was malformed. Erroneous code example: ```compile_fail,E0536 -#[cfg(not())] // error: expected 1 cfg-pattern -pub fn something() {} - -pub fn main() {} +pub fn main() { + if cfg!(not()) { } +} ``` The `not` predicate expects one cfg-pattern. Example: ``` -#[cfg(not(target_os = "linux"))] // ok! -pub fn something() {} - -pub fn main() {} +pub fn main() { + if cfg!(not(target_os = "linux")) { } // ok! +} ``` -For more information about the `cfg` attribute, read the section on +For more information about the `cfg` macro, read the section on [Conditional Compilation][conditional-compilation] in the Reference. [conditional-compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html diff --git a/tests/ui/span/E0536.rs b/tests/ui/span/E0536.rs index 72de7b6f4530..ae0733633541 100644 --- a/tests/ui/span/E0536.rs +++ b/tests/ui/span/E0536.rs @@ -1,4 +1,3 @@ -#[cfg(not())] //~ ERROR E0536 -pub fn something() {} - -pub fn main() {} +pub fn main() { + if cfg!(not()) { } //~ ERROR E0536 +} diff --git a/tests/ui/span/E0536.stderr b/tests/ui/span/E0536.stderr index b0f652208c4a..6c25f9140a1a 100644 --- a/tests/ui/span/E0536.stderr +++ b/tests/ui/span/E0536.stderr @@ -1,8 +1,8 @@ error[E0536]: expected 1 cfg-pattern - --> $DIR/E0536.rs:1:7 + --> $DIR/E0536.rs:2:13 | -LL | #[cfg(not())] - | ^^^^^ +LL | if cfg!(not()) { } + | ^^^^^ error: aborting due to 1 previous error From b5230e53604f1227a087397e561e1cd2329f59b6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 08:06:42 +0000 Subject: [PATCH 51/64] constify `SliceIndex` trait --- library/core/src/range.rs | 16 ++++++++++----- library/core/src/slice/index.rs | 35 ++++++++++++++++++++++----------- library/core/src/str/traits.rs | 27 ++++++++++++++++--------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 2276112a27bb..5cd7956291ca 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -186,14 +186,17 @@ impl IntoBounds for Range { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::Range { #[inline] fn from(value: Range) -> Self { Self { start: value.start, end: value.end } } } + #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for Range { #[inline] fn from(value: legacy::Range) -> Self { Self { start: value.start, end: value.end } @@ -362,7 +365,8 @@ impl IntoBounds for RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeInclusive { #[inline] fn from(value: RangeInclusive) -> Self { Self::new(value.start, value.end) @@ -506,14 +510,16 @@ impl IntoBounds for RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for legacy::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for legacy::RangeFrom { #[inline] fn from(value: RangeFrom) -> Self { Self { start: value.start } } } #[unstable(feature = "new_range_api", issue = "125687")] -impl From> for RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const From> for RangeFrom { #[inline] fn from(value: legacy::RangeFrom) -> Self { Self { start: value.start } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index f725c3fdd94c..c9b8e9c71b49 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -158,6 +158,8 @@ mod private_slice_index { message = "the type `{T}` cannot be indexed by `{Self}`", label = "slice indices are of type `usize` or ranges of `usize`" )] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -208,7 +210,8 @@ pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The methods `index` and `index_mut` panic if the index is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -278,7 +281,8 @@ unsafe impl SliceIndex<[T]> for usize { /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here /// than there are for a general `Range` (which might be `100..3`). -unsafe impl SliceIndex<[T]> for ops::IndexRange { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::IndexRange { type Output = [T]; #[inline] @@ -354,7 +358,8 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -453,7 +458,8 @@ unsafe impl SliceIndex<[T]> for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::Range { type Output = [T]; #[inline] @@ -491,7 +497,8 @@ unsafe impl SliceIndex<[T]> for range::Range { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -529,7 +536,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeTo { /// The methods `index` and `index_mut` panic if the start of the range is out of bounds. #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -574,7 +582,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeFrom { type Output = [T]; #[inline] @@ -611,7 +620,8 @@ unsafe impl SliceIndex<[T]> for range::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -650,7 +660,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeFull { /// - the start of the range is greater than the end of the range or /// - the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -693,7 +704,8 @@ unsafe impl SliceIndex<[T]> for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex<[T]> for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for range::RangeInclusive { type Output = [T]; #[inline] @@ -731,7 +743,8 @@ unsafe impl SliceIndex<[T]> for range::RangeInclusive { /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index b9559c831713..2ed5e686399e 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -92,7 +92,8 @@ const fn str_index_overflow_fail() -> ! { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFull { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFull { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -156,7 +157,8 @@ unsafe impl SliceIndex for ops::RangeFull { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -260,7 +262,8 @@ unsafe impl SliceIndex for ops::Range { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::Range { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -431,7 +434,8 @@ unsafe impl SliceIndex for (ops::Bound, ops::Bound) { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeTo { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeTo { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -499,7 +503,8 @@ unsafe impl SliceIndex for ops::RangeTo { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] -unsafe impl SliceIndex for ops::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -554,7 +559,8 @@ unsafe impl SliceIndex for ops::RangeFrom { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeFrom { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -625,7 +631,8 @@ unsafe impl SliceIndex for range::RangeFrom { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -662,7 +669,8 @@ unsafe impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "new_range_api", issue = "125687")] -unsafe impl SliceIndex for range::RangeInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -713,7 +721,8 @@ unsafe impl SliceIndex for range::RangeInclusive { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex for ops::RangeToInclusive { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { From cb7d52f6430922b5ffd29073f6605b19b80e7f36 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 08:37:09 +0000 Subject: [PATCH 52/64] constify some methods using `SliceIndex` --- library/core/src/ptr/const_ptr.rs | 5 +++-- library/core/src/ptr/mut_ptr.rs | 5 +++-- library/core/src/ptr/non_null.rs | 5 +++-- library/core/src/slice/mod.rs | 20 +++++++++++-------- library/core/src/str/mod.rs | 6 ++++-- .../const-eval/ub-slice-get-unchecked.rs | 3 ++- .../const-eval/ub-slice-get-unchecked.stderr | 12 +++++------ 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 27b0c6830db6..2ad520b7ead7 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1524,10 +1524,11 @@ impl *const [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + pub const unsafe fn get_unchecked(self, index: I) -> *const I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked(self) } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 73efdf044541..579e2461103d 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1881,10 +1881,11 @@ impl *mut [T] { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + pub const unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. unsafe { index.get_unchecked_mut(self) } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index c4ca29a36797..62da6567cca7 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1597,10 +1597,11 @@ impl NonNull<[T]> { /// } /// ``` #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + pub const unsafe fn get_unchecked_mut(self, index: I) -> NonNull where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { // SAFETY: the caller ensures that `self` is dereferenceable and `index` in-bounds. // As a consequence, the resulting pointer cannot be null. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index abcba5a621e2..32419024db95 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -568,9 +568,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get(&self, index: I) -> Option<&I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get(&self, index: I) -> Option<&I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get(self) } @@ -594,9 +595,10 @@ impl [T] { #[rustc_no_implicit_autorefs] #[inline] #[must_use] - pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where - I: SliceIndex, + I: ~const SliceIndex, { index.get_mut(self) } @@ -633,9 +635,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked(&self, index: I) -> &I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked(&self, index: I) -> &I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; // the slice is dereferenceable because `self` is a safe reference. @@ -677,9 +680,10 @@ impl [T] { #[inline] #[must_use] #[track_caller] - pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output + #[rustc_const_unstable(feature = "const_index", issue = "143775")] + pub const unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where - I: SliceIndex, + I: ~const SliceIndex, { // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; // the slice is dereferenceable because `self` is a safe reference. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index fba3436496e3..bb0106b9fd94 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -589,8 +589,9 @@ impl str { /// assert!(v.get(..42).is_none()); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get>(&self, i: I) -> Option<&I::Output> { + pub const fn get>(&self, i: I) -> Option<&I::Output> { i.get(self) } @@ -621,8 +622,9 @@ impl str { /// assert_eq!("HEllo", v); /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_index", issue = "143775")] #[inline] - pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + pub const fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { i.get_mut(self) } diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs index e805ac01c9d0..ad2b49e60498 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs @@ -1,9 +1,10 @@ -//@ known-bug: #110395 +#![feature(const_index, const_trait_impl)] const A: [(); 5] = [(), (), (), (), ()]; // Since the indexing is on a ZST, the addresses are all fine, // but we should still catch the bad range. const B: &[()] = unsafe { A.get_unchecked(3..1) }; +//~^ ERROR: slice::get_unchecked requires that the range is within the slice fn main() {} diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr index 6e428079afe8..88ea310f19c6 100644 --- a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr +++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr @@ -1,11 +1,11 @@ -error[E0015]: cannot call non-const method `core::slice::::get_unchecked::>` in constants - --> $DIR/ub-slice-get-unchecked.rs:7:29 +error[E0080]: evaluation panicked: unsafe precondition(s) violated: slice::get_unchecked requires that the range is within the slice + + This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety. + --> $DIR/ub-slice-get-unchecked.rs:7:27 | LL | const B: &[()] = unsafe { A.get_unchecked(3..1) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `B` failed here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0080`. From 2b4ede7e3d37de731821b5b04a6f1fce269c1afb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 11 Jul 2025 09:24:42 +0000 Subject: [PATCH 53/64] constify `Index` trait and its slice impls --- library/core/src/array/mod.rs | 10 +++-- library/core/src/ops/index.rs | 6 ++- library/core/src/slice/index.rs | 10 +++-- library/core/src/str/traits.rs | 10 +++-- tests/ui/consts/issue-94675.rs | 4 +- tests/ui/consts/issue-94675.stderr | 27 +++++++++---- .../issues/issue-35813-postfix-after-cast.rs | 3 +- .../issue-35813-postfix-after-cast.stderr | 38 +++++++------------ 8 files changed, 60 insertions(+), 48 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 16356f749c92..62203e132b70 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -374,9 +374,10 @@ impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] { } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl Index for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const Index for [T; N] where - [T]: Index, + [T]: ~const Index, { type Output = <[T] as Index>::Output; @@ -387,9 +388,10 @@ where } #[stable(feature = "index_trait_on_arrays", since = "1.50.0")] -impl IndexMut for [T; N] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const IndexMut for [T; N] where - [T]: IndexMut, + [T]: ~const IndexMut, { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 8092fa9eb2fc..d8489e9a9491 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -55,6 +55,8 @@ #[doc(alias = "]")] #[doc(alias = "[")] #[doc(alias = "[]")] +#[const_trait] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] pub trait Index { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -165,7 +167,9 @@ see chapter in The Book : Index { +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +#[const_trait] +pub trait IndexMut: ~const Index { /// Performs the mutable indexing (`container[index]`) operation. /// /// # Panics diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index c9b8e9c71b49..322b3580eded 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -6,9 +6,10 @@ use crate::ub_checks::assert_unsafe_precondition; use crate::{ops, range}; #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { type Output = I::Output; @@ -19,9 +20,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for [T] where - I: SliceIndex<[T]>, + I: ~const SliceIndex<[T]>, { #[inline(always)] fn index_mut(&mut self, index: I) -> &mut I::Output { diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 2ed5e686399e..42ffc591b5bb 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -49,9 +49,10 @@ impl PartialOrd for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::Index for str where - I: SliceIndex, + I: ~const SliceIndex, { type Output = I::Output; @@ -62,9 +63,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for str +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +impl const ops::IndexMut for str where - I: SliceIndex, + I: ~const SliceIndex, { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { diff --git a/tests/ui/consts/issue-94675.rs b/tests/ui/consts/issue-94675.rs index 87c8b04452ba..22791e7d15e5 100644 --- a/tests/ui/consts/issue-94675.rs +++ b/tests/ui/consts/issue-94675.rs @@ -7,7 +7,9 @@ struct Foo<'a> { impl<'a> Foo<'a> { const fn spam(&mut self, baz: &mut Vec) { self.bar[0] = baz.len(); - //~^ ERROR: cannot call + //~^ ERROR: `Vec: [const] Index<_>` is not satisfied + //~| ERROR: `Vec: [const] Index` is not satisfied + //~| ERROR: `Vec: [const] IndexMut` is not satisfied } } diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index 63a86b456332..608ce0cfef01 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -1,13 +1,24 @@ -error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-94675.rs:9:17 +error[E0277]: the trait bound `Vec: [const] Index<_>` is not satisfied + --> $DIR/issue-94675.rs:9:9 | LL | self.bar[0] = baz.len(); - | ^^^ + | ^^^^^^^^^^^ + +error[E0277]: the trait bound `Vec: [const] IndexMut` is not satisfied + --> $DIR/issue-94675.rs:9:9 | -note: impl defined here, but it is not `const` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `Vec: [const] Index` is not satisfied + --> $DIR/issue-94675.rs:9:9 + | +LL | self.bar[0] = baz.len(); + | ^^^^^^^^^^^ + | +note: required by a bound in `std::ops::IndexMut::index_mut` + --> $SRC_DIR/core/src/ops/index.rs:LL:COL -For more information about this error, try `rustc --explain E0015`. +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs index 316c612940c9..439793ea8f72 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.rs @@ -1,6 +1,6 @@ //@ edition:2018 #![crate_type = "lib"] -#![feature(type_ascription)] +#![feature(type_ascription, const_index, const_trait_impl)] use std::future::Future; use std::pin::Pin; @@ -129,7 +129,6 @@ pub fn inside_block() { static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); //~^ ERROR: cast cannot be followed by indexing -//~| ERROR: cannot call non-const operator in statics static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); //~^ ERROR: expected one of diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr index 64cf8baf9a5d..ce7129da9371 100644 --- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr +++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr @@ -219,13 +219,13 @@ LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]); | + + error: expected one of `)`, `,`, `.`, `?`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:134:36 + --> $DIR/issue-35813-postfix-after-cast.rs:133:36 | LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); | ^ expected one of `)`, `,`, `.`, `?`, or an operator error: cast cannot be followed by `?` - --> $DIR/issue-35813-postfix-after-cast.rs:139:5 + --> $DIR/issue-35813-postfix-after-cast.rs:138:5 | LL | Err(0u64) as Result?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,25 +236,25 @@ LL | (Err(0u64) as Result)?; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:141:14 + --> $DIR/issue-35813-postfix-after-cast.rs:140:14 | LL | Err(0u64): Result?; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: expected identifier, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:153:13 + --> $DIR/issue-35813-postfix-after-cast.rs:152:13 | LL | drop_ptr: F(); | ^ expected identifier error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:160:13 + --> $DIR/issue-35813-postfix-after-cast.rs:159:13 | LL | drop_ptr: fn(u8); | ^ expected one of 8 possible tokens error: cast cannot be followed by a function call - --> $DIR/issue-35813-postfix-after-cast.rs:166:5 + --> $DIR/issue-35813-postfix-after-cast.rs:165:5 | LL | drop as fn(u8)(0); | ^^^^^^^^^^^^^^ @@ -265,13 +265,13 @@ LL | (drop as fn(u8))(0); | + + error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:168:13 + --> $DIR/issue-35813-postfix-after-cast.rs:167:13 | LL | drop_ptr: fn(u8)(0); | ^ expected one of 8 possible tokens error: cast cannot be followed by `.await` - --> $DIR/issue-35813-postfix-after-cast.rs:173:5 + --> $DIR/issue-35813-postfix-after-cast.rs:172:5 | LL | Box::pin(noop()) as Pin>>.await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -282,13 +282,13 @@ LL | (Box::pin(noop()) as Pin>>).await; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:176:21 + --> $DIR/issue-35813-postfix-after-cast.rs:175:21 | LL | Box::pin(noop()): Pin>.await; | ^ expected one of `.`, `;`, `?`, `}`, or an operator error: cast cannot be followed by a field access - --> $DIR/issue-35813-postfix-after-cast.rs:188:5 + --> $DIR/issue-35813-postfix-after-cast.rs:187:5 | LL | Foo::default() as Foo.bar; | ^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ LL | (Foo::default() as Foo).bar; | + + error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:` - --> $DIR/issue-35813-postfix-after-cast.rs:190:19 + --> $DIR/issue-35813-postfix-after-cast.rs:189:19 | LL | Foo::default(): Foo.bar; | ^ expected one of `.`, `;`, `?`, `}`, or an operator @@ -322,21 +322,11 @@ LL | if true { 33 } else { 44 }: i32.max(0) | ^ expected one of `,`, `.`, `?`, or an operator error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-35813-postfix-after-cast.rs:151:13 + --> $DIR/issue-35813-postfix-after-cast.rs:150:13 | LL | drop as F(); | ^^^ only `Fn` traits may use parentheses -error[E0015]: cannot call non-const operator in statics - --> $DIR/issue-35813-postfix-after-cast.rs:130:42 - | -LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); - | ^^^^^^ - | - = note: calls in statics are limited to constant functions, tuple structs and tuple variants - = note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)` +error: aborting due to 39 previous errors -error: aborting due to 40 previous errors - -Some errors have detailed explanations: E0015, E0214. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0214`. From cbaaf153a58ed0ebbc9c327c3d61462aef7aee15 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 15 Jul 2025 11:04:07 +0200 Subject: [PATCH 54/64] tidy: check for invalid file names --- src/tools/tidy/src/filenames.rs | 40 +++++++++++++++++++++++++++++++++ src/tools/tidy/src/lib.rs | 1 + src/tools/tidy/src/main.rs | 2 ++ 3 files changed, 43 insertions(+) create mode 100644 src/tools/tidy/src/filenames.rs diff --git a/src/tools/tidy/src/filenames.rs b/src/tools/tidy/src/filenames.rs new file mode 100644 index 000000000000..53115f4eaa41 --- /dev/null +++ b/src/tools/tidy/src/filenames.rs @@ -0,0 +1,40 @@ +//! Tidy check to ensure that there are no filenames containing forbidden characters +//! checked into the source tree by accident: +//! - Non-UTF8 filenames +//! - Control characters such as CR or TAB +//! - Filenames containing ":" as they are not supported on Windows +//! +//! Only files added to git are checked, as it may be acceptable to have temporary +//! invalid filenames in the local directory during development. + +use std::path::Path; +use std::process::Command; + +pub fn check(root_path: &Path, bad: &mut bool) { + let stat_output = Command::new("git") + .arg("-C") + .arg(root_path) + .args(["ls-files", "-z"]) + .output() + .unwrap() + .stdout; + for filename in stat_output.split(|&b| b == 0) { + match str::from_utf8(filename) { + Err(_) => tidy_error!( + bad, + r#"non-UTF8 file names are not supported: "{}""#, + String::from_utf8_lossy(filename), + ), + Ok(name) if name.chars().any(|c| c.is_control()) => tidy_error!( + bad, + r#"control characters are not supported in file names: "{}""#, + String::from_utf8_lossy(filename), + ), + Ok(name) if name.contains(':') => tidy_error!( + bad, + r#"":" is not supported in file names because of Windows compatibility: "{name}""#, + ), + _ => (), + } + } +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 77855392b4da..ade4055b5bd1 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -167,6 +167,7 @@ pub mod error_codes; pub mod ext_tool_checks; pub mod extdeps; pub mod features; +pub mod filenames; pub mod fluent_alphabetical; pub mod fluent_period; mod fluent_used; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index a67f7a511b59..0f1116a632e2 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -155,6 +155,8 @@ fn main() { check!(triagebot, &root_path); + check!(filenames, &root_path); + let collected = { drain_handles(&mut handles); From 14f47009cc5b02cd8c28ca2cc9c1fd58aeeef25b Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 15 Jul 2025 14:57:51 +0200 Subject: [PATCH 55/64] Add InterpCx::fn_abi_of_instance/_fn_ptr with tracing, shadowing FnAbiOf --- .../rustc_const_eval/src/interpret/call.rs | 2 +- .../src/interpret/eval_context.rs | 55 +++++++++++++------ .../rustc_const_eval/src/interpret/step.rs | 1 - src/tools/miri/src/helpers.rs | 2 +- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index ad3e02580f33..1503f3bcd990 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; use rustc_hir::def_id::DefId; -use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, TyAndLayout}; +use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 41fc8d47cd36..11e7706fe605 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,8 +7,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ - self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, - TyAndLayout, + self, FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, + LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; use rustc_middle::{mir, span_bug}; @@ -92,20 +92,6 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } } -impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { - /// This inherent method takes priority over the trait method with the same name in LayoutOf, - /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. - /// See [LayoutOf::layout_of] for the original documentation. - #[inline(always)] - pub fn layout_of( - &self, - ty: Ty<'tcx>, - ) -> as LayoutOfHelpers<'tcx>>::LayoutOfResult { - let _span = enter_trace_span!(M, "InterpCx::layout_of", "ty = {:?}", ty.kind()); - LayoutOf::layout_of(self, ty) - } -} - impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpErrorKind<'tcx>>; @@ -121,6 +107,43 @@ impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { } } +impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + /// This inherent method takes priority over the trait method with the same name in LayoutOf, + /// and allows wrapping the actual [LayoutOf::layout_of] with a tracing span. + /// See [LayoutOf::layout_of] for the original documentation. + #[inline(always)] + pub fn layout_of(&self, ty: Ty<'tcx>) -> >::LayoutOfResult { + let _span = enter_trace_span!(M, "InterpCx::layout_of", ty = ?ty.kind()); + LayoutOf::layout_of(self, ty) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_fn_ptr] with a tracing span. + /// See [FnAbiOf::fn_abi_of_fn_ptr] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_fn_ptr( + &self, + sig: ty::PolyFnSig<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_fn_ptr", ?sig, ?extra_args); + FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args) + } + + /// This inherent method takes priority over the trait method with the same name in FnAbiOf, + /// and allows wrapping the actual [FnAbiOf::fn_abi_of_instance] with a tracing span. + /// See [FnAbiOf::fn_abi_of_instance] for the original documentation. + #[inline(always)] + pub fn fn_abi_of_instance( + &self, + instance: ty::Instance<'tcx>, + extra_args: &'tcx ty::List>, + ) -> >::FnAbiOfResult { + let _span = enter_trace_span!(M, "InterpCx::fn_abi_of_instance", ?instance, ?extra_args); + FnAbiOf::fn_abi_of_instance(self, instance, extra_args) + } +} + /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 833fcc388179..629dcc3523ca 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -5,7 +5,6 @@ use either::Either; use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_index::IndexSlice; -use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index c150dc16b072..f2283f0902b0 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -13,7 +13,7 @@ use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; -use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout}; use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy}; use rustc_session::config::CrateType; use rustc_span::{Span, Symbol}; From 8770e5734ed5e7c1b8bc8b59b73b7f79134e4190 Mon Sep 17 00:00:00 2001 From: Havard Eidnes Date: Mon, 14 Jul 2025 17:03:42 +0000 Subject: [PATCH 56/64] Add `0323pin` as target maintainer, and fix link to pkgsrc-wip and explain. --- src/doc/rustc/src/platform-support/netbsd.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md index e80ff85edad1..b173bf82b440 100644 --- a/src/doc/rustc/src/platform-support/netbsd.md +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -32,10 +32,11 @@ are built for NetBSD 8.x but also work on newer OS versions). ## Target Maintainers [@he32](https://github.com/he32) +[@0323pin](https://github.com/0323pin) Further contacts: -- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust +- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust188/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust. Note that we have the convention of having multiple rust versions active in pkgsrc-wip at any one time, so the version number is part of the directory name, and from time to time old versions are culled so this is not a fully "stable" link. - [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc. - [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself From 078332fdc8e11f7ff8253c019085098538ec3c2a Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 20 Jun 2025 02:48:15 +0000 Subject: [PATCH 57/64] rustdoc-json: Structured attributes Implements https://www.github.com/rust-lang/rust/issues/141358. This has 2 primary benefits: 1. For rustdoc-json consumers, they no longer need to parse strings of attributes, but it's there in a structured and normalized way. 2. For rustc contributors, the output of HIR pretty printing is no longer a versioned thing in the output. People can work on https://github.com/rust-lang/rust/issues/131229 without needing to bump `FORMAT_VERSION`. (Over time, as the attribute refractor continues, I expect we'll add new things to `rustdoc_json_types::Attribute`. But this can be done separately to the rustc changes). --- src/librustdoc/clean/types.rs | 84 +++++----------- src/librustdoc/html/render/mod.rs | 6 +- src/librustdoc/html/render/print_item.rs | 3 +- src/librustdoc/json/conversions.rs | 99 ++++++++++++++++++- src/rustdoc-json-types/lib.rs | 89 ++++++++++++++++- .../attrs/automatically_derived.rs | 2 +- tests/rustdoc-json/attrs/cold.rs | 2 +- tests/rustdoc-json/attrs/export_name_2021.rs | 2 +- tests/rustdoc-json/attrs/export_name_2024.rs | 4 +- tests/rustdoc-json/attrs/inline.rs | 6 +- tests/rustdoc-json/attrs/link_section_2021.rs | 3 +- tests/rustdoc-json/attrs/link_section_2024.rs | 3 +- tests/rustdoc-json/attrs/must_use.rs | 4 +- tests/rustdoc-json/attrs/no_mangle_2021.rs | 2 +- tests/rustdoc-json/attrs/no_mangle_2024.rs | 2 +- tests/rustdoc-json/attrs/non_exhaustive.rs | 6 +- tests/rustdoc-json/attrs/optimize.rs | 6 +- tests/rustdoc-json/attrs/repr_align.rs | 3 +- tests/rustdoc-json/attrs/repr_c.rs | 18 +++- tests/rustdoc-json/attrs/repr_c_int_enum.rs | 11 +++ tests/rustdoc-json/attrs/repr_combination.rs | 25 +++-- tests/rustdoc-json/attrs/repr_int_enum.rs | 15 ++- tests/rustdoc-json/attrs/repr_packed.rs | 8 +- tests/rustdoc-json/attrs/target_feature.rs | 25 +++-- .../rustdoc-json/enums/discriminant/struct.rs | 2 +- .../rustdoc-json/enums/discriminant/tuple.rs | 2 +- tests/rustdoc-json/keyword_private.rs | 4 +- .../visibility/doc_hidden_documented.rs | 6 +- 28 files changed, 318 insertions(+), 124 deletions(-) create mode 100644 tests/rustdoc-json/attrs/repr_c_int_enum.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3ecd41db2ddc..20babc6168b9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -759,79 +759,48 @@ impl Item { Some(tcx.visibility(def_id)) } - fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec { - const ALLOWED_ATTRIBUTES: &[Symbol] = - &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; + /// Get a list of attributes excluding `#[repr]` to display. + /// + /// Only used by the HTML output-format. + fn attributes_without_repr(&self) -> Vec { self.attrs .other_attrs .iter() - .filter_map(|attr| { - if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr { + .filter_map(|attr| match attr { + hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { Some(format!("#[link_section = \"{name}\"]")) } - // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing. - // It is also used by cargo-semver-checks. - else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr { + hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { Some("#[no_mangle]".to_string()) - } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr - { - Some(format!("#[export_name = \"{name}\"]")) - } else if let hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) = attr { - Some("#[non_exhaustive]".to_string()) - } else if is_json { - match attr { - // rustdoc-json stores this in `Item::deprecation`, so we - // don't want it it `Item::attrs`. - hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => None, - // We have separate pretty-printing logic for `#[repr(..)]` attributes. - hir::Attribute::Parsed(AttributeKind::Repr { .. }) => None, - // target_feature is special-cased because cargo-semver-checks uses it - hir::Attribute::Parsed(AttributeKind::TargetFeature(features, _)) => { - let mut output = String::new(); - for (i, (feature, _)) in features.iter().enumerate() { - if i != 0 { - output.push_str(", "); - } - output.push_str(&format!("enable=\"{}\"", feature.as_str())); - } - Some(format!("#[target_feature({output})]")) - } - hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => { - Some("#[automatically_derived]".to_string()) - } - _ => Some({ - let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); - assert_eq!(s.pop(), Some('\n')); - s - }), - } - } else { - if !attr.has_any_name(ALLOWED_ATTRIBUTES) { - return None; - } - Some( - rustc_hir_pretty::attribute_to_string(&tcx, attr) - .replace("\\\n", "") - .replace('\n', "") - .replace(" ", " "), - ) } + hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { + Some(format!("#[export_name = \"{name}\"]")) + } + hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { + Some("#[non_exhaustive]".to_string()) + } + _ => None, }) .collect() } - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec { - let mut attrs = self.attributes_without_repr(tcx, is_json); + /// Get a list of attributes to display on this item. + /// + /// Only used by the HTML output-format. + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec { + let mut attrs = self.attributes_without_repr(); - if let Some(repr_attr) = self.repr(tcx, cache, is_json) { + if let Some(repr_attr) = self.repr(tcx, cache) { attrs.push(repr_attr); } attrs } /// Returns a stringified `#[repr(...)]` attribute. - pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option { - repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json) + /// + /// Only used by the HTML output-format. + pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option { + repr_attributes(tcx, cache, self.def_id()?, self.type_()) } pub fn is_doc_hidden(&self) -> bool { @@ -843,12 +812,14 @@ impl Item { } } +/// Return a string representing the `#[repr]` attribute if present. +/// +/// Only used by the HTML output-format. pub(crate) fn repr_attributes( tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId, item_type: ItemType, - is_json: bool, ) -> Option { use rustc_abi::IntegerType; @@ -865,7 +836,6 @@ pub(crate) fn repr_attributes( // Render `repr(transparent)` iff the non-1-ZST field is public or at least one // field is public in case all fields are 1-ZST fields. let render_transparent = cache.document_private - || is_json || adt .all_fields() .find(|field| { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 70f3f54e4c05..06de4944d97d 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1191,7 +1191,7 @@ fn render_assoc_item( // a whitespace prefix and newline. fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display { fmt::from_fn(move |f| { - for a in it.attributes(cx.tcx(), cx.cache(), false) { + for a in it.attributes(cx.tcx(), cx.cache()) { writeln!(f, "{prefix}{a}")?; } Ok(()) @@ -1207,7 +1207,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) { // When an attribute is rendered inside a tag, it is formatted using // a div to produce a newline after it. fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { - for attr in it.attributes(cx.tcx(), cx.cache(), false) { + for attr in it.attributes(cx.tcx(), cx.cache()) { render_code_attribute(CodeAttribute(attr), w); } } @@ -1219,7 +1219,7 @@ fn render_repr_attributes_in_code( def_id: DefId, item_type: ItemType, ) { - if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) { + if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) { render_code_attribute(CodeAttribute(repr), w); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e33bdc0db32f..667d39e9bc2f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1487,12 +1487,11 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { self.cx.cache(), self.def_id, ItemType::Union, - false, ) { writeln!(f, "{repr}")?; }; } else { - for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) { + for a in self.it.attributes(self.cx.tcx(), self.cx.cache()) { writeln!(f, "{a}")?; } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index e7163bead92e..0a84d8caa30f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -5,10 +5,12 @@ use rustc_abi::ExternAbi; use rustc_ast::ast; use rustc_attr_data_structures::{self as attrs, DeprecatedSince}; +use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_hir::{HeaderSafety, Safety}; use rustc_metadata::rendered_const; +use rustc_middle::ty::TyCtxt; use rustc_middle::{bug, ty}; use rustc_span::{Pos, kw, sym}; use rustdoc_json_types::*; @@ -39,7 +41,12 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes(self.tcx, &self.cache, true); + let attrs = item + .attrs + .other_attrs + .iter() + .filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx)) + .collect(); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::ItemInner { name, item_id, .. } = *item.inner; @@ -886,3 +893,93 @@ impl FromClean for ItemKind { } } } + +/// Maybe convert a attribute from hir to json. +/// +/// Returns `None` if the attribute shouldn't be in the output. +fn maybe_from_hir_attr( + attr: &hir::Attribute, + item_id: ItemId, + tcx: TyCtxt<'_>, +) -> Option { + use attrs::AttributeKind as AK; + + let kind = match attr { + hir::Attribute::Parsed(kind) => kind, + + hir::Attribute::Unparsed(_) => { + // FIXME: We should handle `#[doc(hidden)]`. + return Some(other_attr(tcx, attr)); + } + }; + + Some(match kind { + AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation. + AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), + + AK::MustUse { reason, span: _ } => { + Attribute::MustUse { reason: reason.map(|s| s.to_string()) } + } + AK::Repr { .. } => repr_attr( + tcx, + item_id.as_def_id().expect("all items that could have #[repr] have a DefId"), + ), + AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()), + AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()), + AK::TargetFeature(features, _span) => Attribute::TargetFeature { + enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(), + }, + + AK::NoMangle(_) => Attribute::NoMangle, + AK::NonExhaustive(_) => Attribute::NonExhaustive, + AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived, + + _ => other_attr(tcx, attr), + }) +} + +fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute { + let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr); + assert_eq!(s.pop(), Some('\n')); + Attribute::Other(s) +} + +fn repr_attr(tcx: TyCtxt<'_>, def_id: DefId) -> Attribute { + let repr = tcx.adt_def(def_id).repr(); + + let kind = if repr.c() { + ReprKind::C + } else if repr.transparent() { + ReprKind::Transparent + } else if repr.simd() { + ReprKind::Simd + } else { + ReprKind::Rust + }; + + let align = repr.align.map(|a| a.bytes()); + let packed = repr.pack.map(|p| p.bytes()); + let int = repr.int.map(format_integer_type); + + Attribute::Repr(AttributeRepr { kind, align, packed, int }) +} + +fn format_integer_type(it: rustc_abi::IntegerType) -> String { + use rustc_abi::Integer::*; + use rustc_abi::IntegerType::*; + match it { + Pointer(true) => "isize", + Pointer(false) => "usize", + Fixed(I8, true) => "i8", + Fixed(I8, false) => "u8", + Fixed(I16, true) => "i16", + Fixed(I16, false) => "u16", + Fixed(I32, true) => "i32", + Fixed(I32, false) => "u32", + Fixed(I64, true) => "i64", + Fixed(I64, false) => "u64", + Fixed(I128, true) => "i128", + Fixed(I128, false) => "u128", + } + .to_owned() +} diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 0e72ddd9db1e..6235b0e8576f 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Pretty printing of no_mangle attributes changed -pub const FORMAT_VERSION: u32 = 53; +// Latest feature: Structured Attributes +pub const FORMAT_VERSION: u32 = 54; /// The root of the emitted JSON blob. /// @@ -195,13 +195,94 @@ pub struct Item { /// - `#[repr(C)]` and other reprs also appear as themselves, /// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`. /// Multiple repr attributes on the same item may be combined into an equivalent single attr. - pub attrs: Vec, + pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, /// The type-specific fields describing this item. pub inner: ItemEnum, } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +/// An attribute, e.g. `#[repr(C)]` +/// +/// This doesn't include: +/// - `#[doc = "Doc Comment"]` or `/// Doc comment`. These are in [`Item::docs`] instead. +/// - `#[deprecated]`. These are in [`Item::deprecation`] instead. +pub enum Attribute { + /// `#[non_exhaustive]` + NonExhaustive, + + /// `#[must_use]` + MustUse { reason: Option }, + + /// `#[export_name = "name"]` + ExportName(String), + + /// `#[link_section = "name"]` + LinkSection(String), + + /// `#[automatically_derived]` + AutomaticallyDerived, + + /// `#[repr]` + Repr(AttributeRepr), + + /// `#[no_mangle]` + NoMangle, + + /// #[target_feature(enable = "feature1", enable = "feature2")] + TargetFeature { enable: Vec }, + + /// Something else. + /// + /// Things here are explicitly *not* covered by the [`FORMAT_VERSION`] + /// constant, and may change without bumping the format version. + /// + /// As an implementation detail, this is currently either: + /// 1. A HIR debug printing, like `"#[attr = Optimize(Speed)]"` + /// 2. The attribute as it appears in source form, like + /// `"#[optimize(speed)]"`. + Other(String), +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +/// The contents of a `#[repr(...)]` attribute. +/// +/// Used in [`Attribute::Repr`]. +pub struct AttributeRepr { + /// The representation, e.g. `#[repr(C)]`, `#[repr(transparent)]` + pub kind: ReprKind, + + /// Alignment in bytes, if explicitly specified by `#[repr(align(...)]`. + pub align: Option, + /// Alignment in bytes, if explicitly specified by `#[repr(packed(...)]]`. + pub packed: Option, + + /// The integer type for an enum descriminant, if explicitly specified. + /// + /// e.g. `"i32"`, for `#[repr(C, i32)]` + pub int: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +/// The kind of `#[repr]`. +/// +/// See [AttributeRepr::kind]`. +pub enum ReprKind { + /// `#[repr(Rust)]` + /// + /// Also the default. + Rust, + /// `#[repr(C)]` + C, + /// `#[repr(transparent)] + Transparent, + /// `#[repr(simd)]` + Simd, +} + /// A range of source code. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Span { @@ -1343,7 +1424,7 @@ pub struct Static { /// Is the static `unsafe`? /// - /// This is only true if it's in an `extern` block, and not explicity marked + /// This is only true if it's in an `extern` block, and not explicitly marked /// as `safe`. /// /// ```rust diff --git a/tests/rustdoc-json/attrs/automatically_derived.rs b/tests/rustdoc-json/attrs/automatically_derived.rs index 4e1ab3d145e5..9ba310d3655b 100644 --- a/tests/rustdoc-json/attrs/automatically_derived.rs +++ b/tests/rustdoc-json/attrs/automatically_derived.rs @@ -9,5 +9,5 @@ impl Default for Manual { } } -//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]' +//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["automatically_derived"]' //@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]' diff --git a/tests/rustdoc-json/attrs/cold.rs b/tests/rustdoc-json/attrs/cold.rs index e219345d669c..ec1926e894e4 100644 --- a/tests/rustdoc-json/attrs/cold.rs +++ b/tests/rustdoc-json/attrs/cold.rs @@ -1,3 +1,3 @@ -//@ is "$.index[?(@.name=='cold_fn')].attrs" '["#[attr = Cold]"]' +//@ is "$.index[?(@.name=='cold_fn')].attrs" '[{"other": "#[attr = Cold]"}]' #[cold] pub fn cold_fn() {} diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs index 254e9f6ef5bf..451d9b9eb375 100644 --- a/tests/rustdoc-json/attrs/export_name_2021.rs +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]' #[export_name = "altered"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs index 8129c109306c..7e398db92ab3 100644 --- a/tests/rustdoc-json/attrs/export_name_2024.rs +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -2,8 +2,8 @@ #![no_std] // The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 -// is still `#[export_name = ..]` without the `unsafe` attribute wrapper. +// doesn't mention the `unsafe`. -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '[{"export_name": "altered"}]' #[unsafe(export_name = "altered")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs index b9ea6ab1d10c..2aed49a48a5c 100644 --- a/tests/rustdoc-json/attrs/inline.rs +++ b/tests/rustdoc-json/attrs/inline.rs @@ -1,11 +1,11 @@ -//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[attr = Inline(Hint)]"]' +//@ is "$.index[?(@.name=='just_inline')].attrs" '[{"other": "#[attr = Inline(Hint)]"}]' #[inline] pub fn just_inline() {} -//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[attr = Inline(Always)]"]' +//@ is "$.index[?(@.name=='inline_always')].attrs" '[{"other": "#[attr = Inline(Always)]"}]' #[inline(always)] pub fn inline_always() {} -//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[attr = Inline(Never)]"]' +//@ is "$.index[?(@.name=='inline_never')].attrs" '[{"other": "#[attr = Inline(Never)]"}]' #[inline(never)] pub fn inline_never() {} diff --git a/tests/rustdoc-json/attrs/link_section_2021.rs b/tests/rustdoc-json/attrs/link_section_2021.rs index a1312f4210b4..acd8ecd0e30c 100644 --- a/tests/rustdoc-json/attrs/link_section_2021.rs +++ b/tests/rustdoc-json/attrs/link_section_2021.rs @@ -1,6 +1,7 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +//@ count "$.index[?(@.name=='example')].attrs[*]" 1 +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' #[link_section = ".text"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/link_section_2024.rs b/tests/rustdoc-json/attrs/link_section_2024.rs index edb028451a8e..8107493229b5 100644 --- a/tests/rustdoc-json/attrs/link_section_2024.rs +++ b/tests/rustdoc-json/attrs/link_section_2024.rs @@ -4,6 +4,7 @@ // Since the 2024 edition the link_section attribute must use the unsafe qualification. // However, the unsafe qualification is not shown by rustdoc. -//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +//@ count "$.index[?(@.name=='example')].attrs[*]" 1 +//@ is "$.index[?(@.name=='example')].attrs[*].link_section" '".text"' #[unsafe(link_section = ".text")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index 3ca6f5a75a5a..3f924c5169ca 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[attr = MustUse]"]' +//@ is "$.index[?(@.name=='example')].attrs[*].must_use.reason" null #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[attr = MustUse {reason: \"does nothing if you do not use it\"}]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs[*].must_use.reason" '"does nothing if you do not use it"' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs index 588be7256db5..703dcb56491c 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2021.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]' #[no_mangle] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs index 0d500e20e6c5..8af00eeda6bb 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2024.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 // is still `#[no_mangle]` without the `unsafe` attribute wrapper. -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["no_mangle"]' #[unsafe(no_mangle)] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs index b95f1a8171fd..e4e6c8fd53ba 100644 --- a/tests/rustdoc-json/attrs/non_exhaustive.rs +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyEnum')].attrs" '["non_exhaustive"]' #[non_exhaustive] pub enum MyEnum { First, } pub enum NonExhaustiveVariant { - //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + //@ is "$.index[?(@.name=='Variant')].attrs" '["non_exhaustive"]' #[non_exhaustive] Variant(i64), } -//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyStruct')].attrs" '["non_exhaustive"]' #[non_exhaustive] pub struct MyStruct { pub x: i64, diff --git a/tests/rustdoc-json/attrs/optimize.rs b/tests/rustdoc-json/attrs/optimize.rs index 0bed0ad18c31..5988120ab2f7 100644 --- a/tests/rustdoc-json/attrs/optimize.rs +++ b/tests/rustdoc-json/attrs/optimize.rs @@ -1,13 +1,13 @@ #![feature(optimize_attribute)] -//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]' +//@ is "$.index[?(@.name=='speed')].attrs" '[{"other": "#[attr = Optimize(Speed)]"}]' #[optimize(speed)] pub fn speed() {} -//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]' +//@ is "$.index[?(@.name=='size')].attrs" '[{"other": "#[attr = Optimize(Size)]"}]' #[optimize(size)] pub fn size() {} -//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]' +//@ is "$.index[?(@.name=='none')].attrs" '[{"other": "#[attr = Optimize(DoNotOptimize)]"}]' #[optimize(none)] pub fn none() {} diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs index c6debda7f1c9..f9d3417c4857 100644 --- a/tests/rustdoc-json/attrs/repr_align.rs +++ b/tests/rustdoc-json/attrs/repr_align.rs @@ -1,6 +1,7 @@ #![no_std] -//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]' +//@ count "$.index[?(@.name=='Aligned')].attrs[*]" 1 +//@ is "$.index[?(@.name=='Aligned')].attrs[*].repr.align" 4 #[repr(align(4))] pub struct Aligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs index e6219413f308..89dbc16cb2a9 100644 --- a/tests/rustdoc-json/attrs/repr_c.rs +++ b/tests/rustdoc-json/attrs/repr_c.rs @@ -1,16 +1,28 @@ #![no_std] -//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCStruct')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCStruct')].attrs[*].repr.align" null #[repr(C)] pub struct ReprCStruct(pub i64); -//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCEnum')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCEnum')].attrs[*].repr.align" null #[repr(C)] pub enum ReprCEnum { First, } -//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]' +//@ count "$.index[?(@.name=='ReprCUnion')].attrs" 1 +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.int" null +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='ReprCUnion')].attrs[*].repr.align" null #[repr(C)] pub union ReprCUnion { pub left: i64, diff --git a/tests/rustdoc-json/attrs/repr_c_int_enum.rs b/tests/rustdoc-json/attrs/repr_c_int_enum.rs new file mode 100644 index 000000000000..e90bcf2b5c61 --- /dev/null +++ b/tests/rustdoc-json/attrs/repr_c_int_enum.rs @@ -0,0 +1,11 @@ +//@ count "$.index[?(@.name=='Foo')].attrs" 1 +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.kind" '"c"' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u8"' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.packed" null +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.align" 16 +#[repr(C, u8)] +#[repr(align(16))] +pub enum Foo { + A(bool) = b'A', + B(char) = b'C', +} diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs index 6fe29c5eac09..bd4a8563b6f2 100644 --- a/tests/rustdoc-json/attrs/repr_combination.rs +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -1,35 +1,34 @@ #![no_std] // Combinations of `#[repr(..)]` attributes. -// Rustdoc JSON emits normalized output, regardless of the original source. -//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]' +//@ is "$.index[?(@.name=='ReprCI8')].attrs" '[{"repr":{"align":null,"int":"i8","kind":"c","packed":null}}]' #[repr(C, i8)] pub enum ReprCI8 { First, } -//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]' +//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '[{"repr":{"align":null,"int":"i16","kind":"c","packed":null}}]' #[repr(C)] #[repr(i16)] pub enum SeparateReprCI16 { First, } -//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]' +//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '[{"repr":{"align":null,"int":"usize","kind":"c","packed":null}}]' #[repr(usize, C)] pub enum ReversedReprCUsize { First, } -//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]' +//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":1}}]' #[repr(C, packed)] pub struct ReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' +//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]' #[repr(C)] #[repr(packed(2))] pub struct SeparateReprCPacked { @@ -37,21 +36,21 @@ pub struct SeparateReprCPacked { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' +//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '[{"repr":{"align":null,"int":null,"kind":"c","packed":2}}]' #[repr(packed(2), C)] pub struct ReversedReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]' +//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '[{"repr":{"align":16,"int":null,"kind":"c","packed":null}}]' #[repr(C, align(16))] pub struct ReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]' +//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]' #[repr(C)] #[repr(align(2))] pub struct SeparateReprCAlign { @@ -59,25 +58,25 @@ pub struct SeparateReprCAlign { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]' +//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '[{"repr":{"align":2,"int":null,"kind":"c","packed":null}}]' #[repr(align(2), C)] pub struct ReversedReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' +//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]' #[repr(C, align(16), isize)] pub enum AlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' +//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '[{"repr":{"align":16,"int":"isize","kind":"c","packed":null}}]' #[repr(isize, C, align(16))] pub enum ReorderedAlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]' +//@ is "$.index[?(@.name=='Transparent')].attrs" '[{"repr":{"align":null,"int":null,"kind":"transparent","packed":null}}]' #[repr(transparent)] pub struct Transparent(i64); diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs index 9b09f341d4fe..79e17f53ad90 100644 --- a/tests/rustdoc-json/attrs/repr_int_enum.rs +++ b/tests/rustdoc-json/attrs/repr_int_enum.rs @@ -1,18 +1,27 @@ #![no_std] -//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.int" '"i8"' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='I8')].attrs[*].repr.packed" null #[repr(i8)] pub enum I8 { First, } -//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.int" '"i32"' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='I32')].attrs[*].repr.packed" null #[repr(i32)] pub enum I32 { First, } -//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.int" '"usize"' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.kind" '"rust"' +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.align" null +//@ is "$.index[?(@.name=='Usize')].attrs[*].repr.packed" null #[repr(usize)] pub enum Usize { First, diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs index 9f3fd86c4b03..ab573835b45c 100644 --- a/tests/rustdoc-json/attrs/repr_packed.rs +++ b/tests/rustdoc-json/attrs/repr_packed.rs @@ -1,16 +1,18 @@ #![no_std] // Note the normalization: -// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON. +// `#[repr(packed)]` in source becomes `{"repr": {"packed": 1, ...}}` in rustdoc JSON. // -//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]' +//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.packed" 1 +//@ is "$.index[?(@.name=='Packed')].attrs[*].repr.kind" '"rust"' #[repr(packed)] pub struct Packed { a: i8, b: i64, } -//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]' +//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.packed" 4 +//@ is "$.index[?(@.name=='PackedAligned')].attrs[*].repr.kind" '"rust"' #[repr(packed(4))] pub struct PackedAligned { a: i8, diff --git a/tests/rustdoc-json/attrs/target_feature.rs b/tests/rustdoc-json/attrs/target_feature.rs index 01bc4f54d322..efe3752c1660 100644 --- a/tests/rustdoc-json/attrs/target_feature.rs +++ b/tests/rustdoc-json/attrs/target_feature.rs @@ -1,38 +1,49 @@ -//@ is "$.index[?(@.name=='test1')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='test1')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test1')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test1')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub fn test1() {} -//@ is "$.index[?(@.name=='test2')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]' //@ is "$.index[?(@.name=='test2')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test2')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test2')].attrs[*].target_feature.enable" '["avx", "avx2"]' #[target_feature(enable = "avx,avx2")] pub fn test2() {} -//@ is "$.index[?(@.name=='test3')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\")]"]' //@ is "$.index[?(@.name=='test3')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test3')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test3')].attrs[*].target_feature.enable" '["avx", "avx2"]' #[target_feature(enable = "avx", enable = "avx2")] pub fn test3() {} -//@ is "$.index[?(@.name=='test4')].attrs" '["#[target_feature(enable=\"avx\", enable=\"avx2\", enable=\"avx512f\")]"]' //@ is "$.index[?(@.name=='test4')].inner.function.header.is_unsafe" false +//@ count "$.index[?(@.name=='test4')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test4')].attrs[*].target_feature.enable" '["avx", "avx2", "avx512f"]' #[target_feature(enable = "avx", enable = "avx2,avx512f")] pub fn test4() {} -//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' +//@ count "$.index[?(@.name=='test5')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test5')].attrs[*].target_feature.enable" '["avx", "avx2"]' +#[target_feature(enable = "avx")] +#[target_feature(enable = "avx2")] +pub fn test5() {} + //@ is "$.index[?(@.name=='test_unsafe_fn')].inner.function.header.is_unsafe" true +//@ count "$.index[?(@.name=='test_unsafe_fn')].attrs[*]" 1 +//@ is "$.index[?(@.name=='test_unsafe_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub unsafe fn test_unsafe_fn() {} pub struct Example; impl Example { - //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='safe_assoc_fn')].inner.function.header.is_unsafe" false + //@ is "$.index[?(@.name=='safe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub fn safe_assoc_fn() {} - //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs" '["#[target_feature(enable=\"avx\")]"]' //@ is "$.index[?(@.name=='unsafe_assoc_fn')].inner.function.header.is_unsafe" true + //@ is "$.index[?(@.name=='unsafe_assoc_fn')].attrs[*].target_feature.enable" '["avx"]' #[target_feature(enable = "avx")] pub unsafe fn unsafe_assoc_fn() {} } diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index ea669e6a0b30..fed0e545798a 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,5 +1,5 @@ #[repr(i32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"i32"' pub enum Foo { //@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index 1b8e791eb230..54bba76a0634 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,5 +1,5 @@ #[repr(u32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' +//@ is "$.index[?(@.name=='Foo')].attrs[*].repr.int" '"u32"' pub enum Foo { //@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index fea546c9fb60..3198fc2529ef 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -5,7 +5,7 @@ //@ !has "$.index[?(@.name=='match')]" //@ has "$.index[?(@.name=='foo')]" -//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' +//@ is "$.index[?(@.name=='foo')].attrs[*].other" '"#[doc(keyword = \"match\")]"' //@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! @@ -13,7 +13,7 @@ pub mod foo {} //@ !has "$.index[?(@.name=='break')]" //@ has "$.index[?(@.name=='bar')]" -//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]' +//@ is "$.index[?(@.name=='bar')].attrs[*].other" '"#[doc(keyword = \"break\")]"' //@ is "$.index[?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "break")] /// hello diff --git a/tests/rustdoc-json/visibility/doc_hidden_documented.rs b/tests/rustdoc-json/visibility/doc_hidden_documented.rs index 6e9ef48680be..f05e4f9d92d5 100644 --- a/tests/rustdoc-json/visibility/doc_hidden_documented.rs +++ b/tests/rustdoc-json/visibility/doc_hidden_documented.rs @@ -1,15 +1,15 @@ //@ compile-flags: --document-hidden-items #![no_std] -//@ is "$.index[?(@.name=='func')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='func')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub fn func() {} -//@ is "$.index[?(@.name=='Unit')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='Unit')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub struct Unit; -//@ is "$.index[?(@.name=='hidden')].attrs" '["#[doc(hidden)]"]' +//@ is "$.index[?(@.name=='hidden')].attrs" '[{"other": "#[doc(hidden)]"}]' #[doc(hidden)] pub mod hidden { //@ is "$.index[?(@.name=='Inner')].attrs" '[]' From 1120cb2fe54fae7a1a8ccd5beb941f5b207084c0 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 15 Jul 2025 14:14:22 -0500 Subject: [PATCH 58/64] Add LocalKey::update --- library/std/src/thread/local.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 7cd448733130..0ad014ccd3e2 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -469,6 +469,29 @@ impl LocalKey> { pub fn replace(&'static self, value: T) -> T { self.with(|cell| cell.replace(value)) } + + /// Updates the contained value using a function. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_update)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell = const { Cell::new(5) }; + /// } + /// + /// X.update(|x| x + 1); + /// assert_eq!(X.get(), 6); + /// ``` + #[unstable(feature = "local_key_cell_update", issue = "143989")] + pub fn update(&'static self, f: impl FnOnce(T) -> T) + where + T: Copy, + { + self.with(|cell| cell.update(f)) + } } impl LocalKey> { From 10bc064d892be46c68b43a1ff8eb6b30abde5fdb Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 15 Jul 2025 18:32:00 -0700 Subject: [PATCH 59/64] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index eabb4cd923de..6833aa715d72 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit eabb4cd923deb73e714f7ad3f5234d68ca284dbe +Subproject commit 6833aa715d724437dc1247d0166afe314ab6854e From 262d02e6fd1fd1b595f19ac33b4693e431c24832 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 16 Jul 2025 01:57:22 +0000 Subject: [PATCH 60/64] Ensure home directory exists This works around a missing mingw home directory in CI --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e92afc14c20d..dc8ac539a3a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,6 +182,11 @@ jobs: - name: install MinGW run: src/ci/scripts/install-mingw.sh + # Workaround for spurious ci failures after mingw install + # see https://rust-lang.zulipchat.com/#narrow/channel/242791-t-infra/topic/Spurious.20bors.20CI.20failures/near/528915775 + - name: ensure home dir exists + run: mkdir -p ~ + - name: install ninja run: src/ci/scripts/install-ninja.sh From babe2c0d0f091f5ea9935176b478ea45b152e49e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 4 Jul 2025 22:21:31 +0300 Subject: [PATCH 61/64] resolve: Merge `NameBindingKind::Module` into `NameBindingKind::Res` --- compiler/rustc_hir/src/def.rs | 15 ++++++ .../src/rmeta/decoder/cstore_impl.rs | 7 +-- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- .../rustc_resolve/src/build_reduced_graph.rs | 50 ++++++------------- compiler/rustc_resolve/src/diagnostics.rs | 40 +++++---------- compiler/rustc_resolve/src/ident.rs | 6 +-- compiler/rustc_resolve/src/imports.rs | 3 -- .../rustc_resolve/src/late/diagnostics.rs | 6 +-- compiler/rustc_resolve/src/lib.rs | 29 +++-------- tests/ui/proc-macro/meta-macro-hygiene.stdout | 6 --- .../nonterminal-token-hygiene.stdout | 6 --- 11 files changed, 61 insertions(+), 111 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index df010f870982..ca57c4f31641 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -295,6 +295,12 @@ impl DefKind { } } + /// This is a "module" in name resolution sense. + #[inline] + pub fn is_module_like(self) -> bool { + matches!(self, DefKind::Mod | DefKind::Enum | DefKind::Trait) + } + #[inline] pub fn is_fn_like(self) -> bool { matches!( @@ -720,6 +726,15 @@ impl Res { } } + /// If this is a "module" in name resolution sense, return its `DefId`. + #[inline] + pub fn module_like_def_id(&self) -> Option { + match self { + Res::Def(def_kind, def_id) if def_kind.is_module_like() => Some(*def_id), + _ => None, + } + } + /// A human readable name for the res kind ("function", "module", etc.). pub fn descr(&self) -> &'static str { match *self { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 19954459cb59..57a672c45f7b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -3,7 +3,7 @@ use std::mem; use std::sync::Arc; use rustc_attr_data_structures::Deprecation; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; @@ -510,10 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } Entry::Vacant(entry) => { entry.insert(parent); - if matches!( - child.res, - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _) - ) { + if child.res.module_like_def_id().is_some() { bfs_queue.push_back(def_id); } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7c48a4b0885e..8f0f9b21dc16 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3454,9 +3454,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N collect_fn(&child.ident, ns, def_id); } - if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait) - && seen_defs.insert(def_id) - { + if defkind.is_module_like() && seen_defs.insert(def_id) { queue.push(def_id); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6979d89a8e7b..a51cdbe76ee3 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -39,21 +39,6 @@ use crate::{ type Res = def::Res; -impl<'ra, Id: Into> ToNameBinding<'ra> - for (Module<'ra>, ty::Visibility, Span, LocalExpnId) -{ - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Module(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - impl<'ra, Id: Into> ToNameBinding<'ra> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { arenas.alloc_name_binding(NameBindingData { @@ -121,7 +106,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !def_id.is_local() { // Query `def_kind` is not used because query system overhead is too expensive here. let def_kind = self.cstore().def_kind_untracked(def_id); - if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind { + if def_kind.is_module_like() { let parent = self .tcx .opt_parent(def_id) @@ -223,12 +208,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let expansion = parent_scope.expansion; // Record primary definitions. match res { - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => { - let module = self.expect_module(def_id); - self.define(parent, ident, TypeNS, (module, vis, span, expansion)); - } Res::Def( - DefKind::Struct + DefKind::Mod + | DefKind::Enum + | DefKind::Trait + | DefKind::Struct | DefKind::Union | DefKind::Variant | DefKind::TyAlias @@ -766,7 +750,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + + if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { + self.r.mods_with_parse_errors.insert(def_id); + } + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -774,14 +763,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { parent.no_implicit_prelude || ast::attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - - if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { - self.r.mods_with_parse_errors.insert(def_id); - } - - // Descend into the module. - self.parent_scope.module = module; } // These items live in the value namespace. @@ -804,15 +785,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), item.span, parent.no_implicit_prelude, ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.parent_scope.module = module; } // These items live in both the type and value namespaces. @@ -920,8 +901,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); + let res = module.res().unwrap(); let vis = ty::Visibility::::Public; - let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas); + let binding = (res, vis, sp, expansion).to_name_binding(self.r.arenas); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 93d848787ef4..11e4a729ae23 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -232,12 +232,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - let old_kind = match (ns, old_binding.module()) { + let old_kind = match (ns, old_binding.res()) { (ValueNS, _) => "value", (MacroNS, _) => "macro", (TypeNS, _) if old_binding.is_extern_crate() => "extern crate", - (TypeNS, Some(module)) if module.is_normal() => "module", - (TypeNS, Some(module)) if module.is_trait() => "trait", + (TypeNS, Res::Def(DefKind::Mod, _)) => "module", + (TypeNS, Res::Def(DefKind::Trait, _)) => "trait", (TypeNS, _) => "type", }; @@ -1319,7 +1319,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // collect submodules to explore - if let Some(module) = name_binding.module() { + if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); @@ -1339,14 +1339,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !is_extern_crate_that_also_appears_in_prelude || alias_import { // add the module to the lookup - if seen_modules.insert(module.def_id()) { + if seen_modules.insert(def_id) { if via_import { &mut worklist_via_import } else { &mut worklist }.push( ( - module, + this.expect_module(def_id), path_segments, child_accessible, child_doc_visible, - is_stable && this.is_stable(module.def_id(), name_binding.span), + is_stable && this.is_stable(def_id, name_binding.span), ), ); } @@ -2094,7 +2094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, // re-export )); } - NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} + NameBindingKind::Res(_) => {} } let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); @@ -2306,25 +2306,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .ok() }; if let Some(binding) = binding { - let mut found = |what| { - msg = format!( - "expected {}, found {} `{}` in {}", - ns.descr(), - what, - ident, - parent - ) - }; - if binding.module().is_some() { - found("module") - } else { - match binding.res() { - // Avoid using TyCtxt::def_kind_descr in the resolver, because it - // indirectly *calls* the resolver, and would cause a query cycle. - Res::Def(kind, id) => found(kind.descr(id)), - _ => found(ns_to_try.descr()), - } - } + msg = format!( + "expected {}, found {} `{ident}` in {parent}", + ns.descr(), + binding.res().descr(), + ); }; } (msg, None) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 99297de40d58..04f9e35b6b46 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1637,11 +1637,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(next_module) = binding.module() { - if self.mods_with_parse_errors.contains(&next_module.def_id()) { + if let Some(def_id) = binding.res().module_like_def_id() { + if self.mods_with_parse_errors.contains(&def_id) { module_had_parse_errors = true; } - module = Some(ModuleOrUniformRoot::Module(next_module)); + module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); record_segment_res(self, res); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 40c63a3edf3c..2fa20b254698 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -679,9 +679,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { NameBindingKind::Res(res) => { Some(self.def_id_to_node_id(res.def_id().expect_local())) } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id(module.def_id().expect_local())) - } NameBindingKind::Import { import, .. } => import.id(), }; if let Some(binding_id) = binding_id { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b669796bb021..a4601cb44ebf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2656,18 +2656,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if result.is_some() || !name_binding.vis.is_visible_locally() { return; } - if let Some(module) = name_binding.module() { + if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id(); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( - module, + r.expect_module(module_def_id), ImportSuggestion { did: Some(def_id), descr: "module", @@ -2682,6 +2681,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { // add the module to the lookup if seen_modules.insert(module_def_id) { + let module = r.expect_module(module_def_id); worklist.push((module, path_segments, doc_visible)); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c2b3451d4a1d..eb2b92604836 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -674,7 +674,6 @@ impl<'ra> Module<'ra> { } } - // Public for rustdoc. fn def_id(self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } @@ -782,7 +781,6 @@ impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { #[derive(Clone, Copy, Debug)] enum NameBindingKind<'ra> { Res(Res), - Module(Module<'ra>), Import { binding: NameBinding<'ra>, import: Import<'ra> }, } @@ -875,18 +873,9 @@ struct AmbiguityError<'ra> { } impl<'ra> NameBindingData<'ra> { - fn module(&self) -> Option> { - match self.kind { - NameBindingKind::Module(module) => Some(module), - NameBindingKind::Import { binding, .. } => binding.module(), - _ => None, - } - } - fn res(&self) -> Res { match self.kind { NameBindingKind::Res(res) => res, - NameBindingKind::Module(module) => module.res().unwrap(), NameBindingKind::Import { binding, .. } => binding.res(), } } @@ -921,7 +910,7 @@ impl<'ra> NameBindingData<'ra> { DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, )) => true, - NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, + NameBindingKind::Res(..) => false, } } @@ -930,11 +919,7 @@ impl<'ra> NameBindingData<'ra> { NameBindingKind::Import { import, .. } => { matches!(import.kind, ImportKind::ExternCrate { .. }) } - NameBindingKind::Module(module) - if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind => - { - def_id.is_crate_root() - } + NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(), _ => false, } } @@ -1279,7 +1264,8 @@ impl<'ra> ResolverArenas<'ra> { if let Some(def_id) = def_id { module_map.insert(def_id, module); let vis = ty::Visibility::::Public; - let binding = (module, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); + let res = module.res().unwrap(); + let binding = (res, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); module_self_bindings.insert(module, binding); } module @@ -1838,7 +1824,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.ensure_traits(self); let traits = module.traits.borrow(); for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { - if self.trait_may_have_item(trait_binding.module(), assoc_item) { + let trait_module = self.get_module(trait_binding.res().def_id()); + if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); found_traits.push(TraitCandidate { def_id, import_ids }); @@ -2174,9 +2161,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? }; - let crate_root = self.expect_module(crate_id.as_def_id()); + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); let vis = ty::Visibility::::Public; - (crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) + (res, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) }) }); diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 1734b9afe92e..91d16eca1b0a 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -49,12 +49,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 42257312a872..63741326e341 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -72,12 +72,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) From 01b546a19b36bebddc8fbb175837a1d90010d8bd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 4 Jul 2025 23:53:34 +0300 Subject: [PATCH 62/64] resolve: Remove trait `ToNameBinding` --- .../rustc_resolve/src/build_reduced_graph.rs | 83 ++++++++++--------- compiler/rustc_resolve/src/ident.rs | 13 +-- compiler/rustc_resolve/src/imports.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 57 ++++++++----- compiler/rustc_resolve/src/macros.rs | 7 +- 5 files changed, 84 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a51cdbe76ee3..4065dbca6751 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -33,39 +33,42 @@ use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::{ BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError, errors, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, + VisResolutionError, errors, }; type Res = def::Res; -impl<'ra, Id: Into> ToNameBinding<'ra> for (Res, ty::Visibility, Span, LocalExpnId) { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Res(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. - pub(crate) fn define(&mut self, parent: Module<'ra>, ident: Ident, ns: Namespace, def: T) - where - T: ToNameBinding<'ra>, - { - let binding = def.to_name_binding(self.arenas); + pub(crate) fn define_binding( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + binding: NameBinding<'ra>, + ) { let key = self.new_disambiguated_key(ident, ns); if let Err(old_binding) = self.try_define(parent, key, binding, false) { self.report_conflict(parent, ident, ns, old_binding, binding); } } + fn define( + &mut self, + parent: Module<'ra>, + ident: Ident, + ns: Namespace, + res: Res, + vis: ty::Visibility>, + span: Span, + expn_id: LocalExpnId, + ) { + let binding = self.arenas.new_res_binding(res, vis.to_def_id(), span, expn_id); + self.define_binding(parent, ident, ns, binding) + } + /// Walks up the tree of definitions starting at `def_id`, /// stopping at the first encountered module. /// Parent block modules for arbitrary def-ids are not recorded for the local crate, @@ -223,7 +226,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _, ) | Res::PrimTy(..) - | Res::ToolMod => self.define(parent, ident, TypeNS, (res, vis, span, expansion)), + | Res::ToolMod => self.define(parent, ident, TypeNS, res, vis, span, expansion), Res::Def( DefKind::Fn | DefKind::AssocFn @@ -232,9 +235,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | DefKind::AssocConst | DefKind::Ctor(..), _, - ) => self.define(parent, ident, ValueNS, (res, vis, span, expansion)), + ) => self.define(parent, ident, ValueNS, res, vis, span, expansion), Res::Def(DefKind::Macro(..), _) | Res::NonMacroAttr(..) => { - self.define(parent, ident, MacroNS, (res, vis, span, expansion)) + self.define(parent, ident, MacroNS, res, vis, span, expansion) } Res::Def( DefKind::TyParam @@ -698,7 +701,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let expansion = parent_scope.expansion; // Define a name in the type namespace if it is not anonymous. - self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion)); + self.r.define(parent, ident, TypeNS, adt_res, adt_vis, adt_span, expansion); self.r.feed_visibility(feed, adt_vis); let def_id = feed.key(); @@ -750,7 +753,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { self.r.mods_with_parse_errors.insert(def_id); @@ -769,10 +772,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Const(box ConstItem { ident, .. }) | ItemKind::Delegation(box Delegation { ident, .. }) | ItemKind::Static(box StaticItem { ident, .. }) => { - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); } ItemKind::Fn(box Fn { ident, .. }) => { - self.r.define(parent, ident, ValueNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, res, vis, sp, expansion); // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). @@ -781,11 +784,11 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // These items live in the type namespace. ItemKind::TyAlias(box TyAlias { ident, .. }) | ItemKind::TraitAlias(ident, ..) => { - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); } ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + self.r.define(parent, ident, TypeNS, res, vis, sp, expansion); self.parent_scope.module = self.r.new_module( Some(parent), @@ -837,7 +840,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); + self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, sp, expansion); self.r.feed_visibility(feed, ctor_vis); // We need the field visibility spans also for the constructor for E0603. self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields()); @@ -901,9 +904,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let res = module.res().unwrap(); - let vis = ty::Visibility::::Public; - let binding = (res, vis, sp, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_pub_res_binding(module.res().unwrap(), sp, expansion); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); @@ -960,7 +961,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } } - self.r.define(parent, ident, TypeNS, imported_binding); + self.r.define_binding(parent, ident, TypeNS, imported_binding); } /// Constructs the reduced graph for one foreign item. @@ -977,7 +978,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); - self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); self.r.feed_visibility(feed, vis); } @@ -1217,7 +1218,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } else { ty::Visibility::Restricted(CRATE_DEF_ID) }; - let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); + let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); self.r.set_binding_parent_module(binding, parent_scope.module); self.r.all_macro_rules.insert(ident.name); if is_macro_export { @@ -1236,7 +1237,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); - self.r.define(self.r.graph_root, ident, MacroNS, import_binding); + self.r.define_binding(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id); @@ -1264,7 +1265,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if !vis.is_public() { self.insert_unused_macro(ident, def_id, item.id); } - self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); + self.r.define(module, ident, MacroNS, res, vis, span, expansion); self.r.feed_visibility(feed, vis); self.parent_scope.macro_rules } @@ -1400,7 +1401,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { if ctxt == AssocCtxt::Trait { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; - self.r.define(parent, ident, ns, (self.res(def_id), vis, item.span, expansion)); + self.r.define(parent, ident, ns, self.res(def_id), vis, item.span, expansion); } else if !matches!(&item.kind, AssocItemKind::Delegation(deleg) if deleg.from_glob) { let impl_def_id = self.r.tcx.local_parent(local_def_id); let key = BindingKey::new(ident.normalize_to_macros_2_0(), ns); @@ -1485,7 +1486,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(variant.id); let def_id = feed.key(); let vis = self.resolve_visibility(&variant.vis); - self.r.define(parent, ident, TypeNS, (self.res(def_id), vis, variant.span, expn_id)); + self.r.define(parent, ident, TypeNS, self.res(def_id), vis, variant.span, expn_id); self.r.feed_visibility(feed, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. @@ -1501,7 +1502,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let feed = self.r.feed(ctor_node_id); let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); - self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); + self.r.define(parent, ident, ValueNS, ctor_res, ctor_vis, variant.span, expn_id); self.r.feed_visibility(feed, ctor_vis); } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 04f9e35b6b46..84d66c15f00c 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -3,11 +3,10 @@ use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; -use rustc_middle::{bug, ty}; +use rustc_middle::bug; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; -use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Span, kw, sym}; use tracing::{debug, instrument}; @@ -20,11 +19,9 @@ use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, ToNameBinding, Used, Weak, errors, + ScopeSet, Segment, Used, Weak, errors, }; -type Visibility = ty::Visibility; - #[derive(Copy, Clone)] pub enum UsePrelude { No, @@ -464,13 +461,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { - let binding = ( + let binding = this.arenas.new_pub_res_binding( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat), - Visibility::Public, derive.span, LocalExpnId::ROOT, - ) - .to_name_binding(this.arenas); + ); result = Ok((binding, Flags::empty())); break; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 2fa20b254698..59896ee88f4c 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -872,7 +872,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - this.define(parent, target, ns, imported_binding); + this.define_binding(parent, target, ns, imported_binding); PendingBinding::Ready(Some(imported_binding)) } Err(Determinacy::Determined) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index eb2b92604836..cf106a4892c7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -768,16 +768,6 @@ impl std::hash::Hash for NameBindingData<'_> { } } -trait ToNameBinding<'ra> { - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra>; -} - -impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { - fn to_name_binding(self, _: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - self - } -} - #[derive(Clone, Copy, Debug)] enum NameBindingKind<'ra> { Res(Res), @@ -1240,6 +1230,32 @@ pub struct ResolverArenas<'ra> { } impl<'ra> ResolverArenas<'ra> { + fn new_res_binding( + &'ra self, + res: Res, + vis: ty::Visibility, + span: Span, + expansion: LocalExpnId, + ) -> NameBinding<'ra> { + self.alloc_name_binding(NameBindingData { + kind: NameBindingKind::Res(res), + ambiguity: None, + warn_ambiguity: false, + vis, + span, + expansion, + }) + } + + fn new_pub_res_binding( + &'ra self, + res: Res, + span: Span, + expn_id: LocalExpnId, + ) -> NameBinding<'ra> { + self.new_res_binding(res, Visibility::Public, span, expn_id) + } + fn new_module( &'ra self, parent: Option>, @@ -1263,9 +1279,8 @@ impl<'ra> ResolverArenas<'ra> { } if let Some(def_id) = def_id { module_map.insert(def_id, module); - let vis = ty::Visibility::::Public; let res = module.res().unwrap(); - let binding = (res, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); + let binding = self.new_pub_res_binding(res, module.span, LocalExpnId::ROOT); module_self_bindings.insert(module, binding); } module @@ -1456,8 +1471,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let registered_tools = tcx.registered_tools(()); - - let pub_vis = ty::Visibility::::Public; let edition = tcx.sess.edition(); let mut resolver = Resolver { @@ -1506,12 +1519,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_expanded_macro_export_errors: BTreeSet::new(), arenas, - dummy_binding: (Res::Err, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas), + dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_types_bindings: PrimTy::ALL .iter() .map(|prim_ty| { - let binding = (Res::PrimTy(*prim_ty), pub_vis, DUMMY_SP, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::PrimTy(*prim_ty); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (prim_ty.name(), binding) }) .collect(), @@ -1519,16 +1532,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .iter() .map(|builtin_attr| { let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(builtin_attr.name)); - let binding = - (res, pub_vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(arenas); + let binding = arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); (builtin_attr.name, binding) }) .collect(), registered_tool_bindings: registered_tools .iter() .map(|ident| { - let binding = (Res::ToolMod, pub_vis, ident.span, LocalExpnId::ROOT) - .to_name_binding(arenas); + let res = Res::ToolMod; + let binding = arenas.new_pub_res_binding(res, ident.span, LocalExpnId::ROOT); (*ident, binding) }) .collect(), @@ -2162,8 +2174,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? }; let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - let vis = ty::Visibility::::Public; - (res, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) }) }); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index cbb24289f51f..c17d74659db3 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -20,7 +20,7 @@ use rustc_expand::expand::{ use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; -use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility}; +use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, @@ -41,7 +41,7 @@ use crate::imports::Import; use crate::{ BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, ToNameBinding, Used, + Resolver, ScopeSet, Segment, Used, }; type Res = def::Res; @@ -436,8 +436,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { .iter() .map(|(_, ident)| { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); - let binding = (res, Visibility::::Public, ident.span, expn_id) - .to_name_binding(self.arenas); + let binding = self.arenas.new_pub_res_binding(res, ident.span, expn_id); (*ident, binding) }) .collect(); From 1a9a226058a31fab77229afc4b0e04c259c64112 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 5 Jul 2025 00:43:52 +0300 Subject: [PATCH 63/64] resolve: Import `ty::Visibility` everywhere --- .../rustc_resolve/src/build_reduced_graph.rs | 44 +++++++++---------- compiler/rustc_resolve/src/imports.rs | 9 ++-- compiler/rustc_resolve/src/late.rs | 8 ++-- compiler/rustc_resolve/src/lib.rs | 20 ++++----- 4 files changed, 39 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 4065dbca6751..5a1be618ceea 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -20,9 +20,9 @@ use rustc_hir::def::{self, *}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::LoadedMacro; +use rustc_middle::bug; use rustc_middle::metadata::ModChild; -use rustc_middle::ty::Feed; -use rustc_middle::{bug, ty}; +use rustc_middle::ty::{Feed, Visibility}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::{Ident, Span, Symbol, kw, sym}; use tracing::debug; @@ -61,7 +61,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident: Ident, ns: Namespace, res: Res, - vis: ty::Visibility>, + vis: Visibility>, span: Span, expn_id: LocalExpnId, ) { @@ -281,10 +281,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { Res::Def(self.r.tcx.def_kind(def_id), def_id) } - fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { + fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility { self.try_resolve_visibility(vis, true).unwrap_or_else(|err| { self.r.report_vis_error(err); - ty::Visibility::Public + Visibility::Public }) } @@ -292,10 +292,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { &mut self, vis: &'ast ast::Visibility, finalize: bool, - ) -> Result> { + ) -> Result> { let parent_scope = &self.parent_scope; match vis.kind { - ast::VisibilityKind::Public => Ok(ty::Visibility::Public), + ast::VisibilityKind::Public => Ok(Visibility::Public), ast::VisibilityKind::Inherited => { Ok(match self.parent_scope.module.kind { // Any inherited visibility resolved directly inside an enum or trait @@ -305,7 +305,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.tcx.visibility(def_id).expect_local() } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted( + _ => Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), }) @@ -353,9 +353,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } if module.is_normal() { match res { - Res::Err => Ok(ty::Visibility::Public), + Res::Err => Ok(Visibility::Public), _ => { - let vis = ty::Visibility::Restricted(res.def_id()); + let vis = Visibility::Restricted(res.def_id()); if self.r.is_accessible_from(vis, parent_scope.module) { Ok(vis.expect_local()) } else { @@ -420,7 +420,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &ast::Item, root_span: Span, root_id: NodeId, - vis: ty::Visibility, + vis: Visibility, ) { let current_module = self.parent_scope.module; let import = self.r.arenas.alloc_import(ImportData { @@ -468,7 +468,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { list_stem: bool, // The whole `use` item item: &Item, - vis: ty::Visibility, + vis: Visibility, root_span: Span, ) { debug!( @@ -677,7 +677,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { true, // The whole `use` item item, - ty::Visibility::Restricted( + Visibility::Restricted( self.parent_scope.module.nearest_parent_mod().expect_local(), ), root_span, @@ -693,7 +693,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ident: Ident, feed: Feed<'tcx, LocalDefId>, adt_res: Res, - adt_vis: ty::Visibility, + adt_vis: Visibility, adt_span: Span, ) { let parent_scope = &self.parent_scope; @@ -818,7 +818,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let mut ctor_vis = if vis.is_public() && ast::attr::contains_name(&item.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -831,7 +831,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // constructor visibility should still be determined correctly. let field_vis = self .try_resolve_visibility(&field.vis, false) - .unwrap_or(ty::Visibility::Public); + .unwrap_or(Visibility::Public); if ctor_vis.is_at_least(field_vis, self.r.tcx) { ctor_vis = field_vis; } @@ -880,7 +880,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { item: &Item, ident: Ident, local_def_id: LocalDefId, - vis: ty::Visibility, + vis: Visibility, parent: Module<'ra>, ) { let sp = item.span; @@ -1064,7 +1064,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { root_span: span, span, module_path: Vec::new(), - vis: ty::Visibility::Restricted(CRATE_DEF_ID), + vis: Visibility::Restricted(CRATE_DEF_ID), }) }; @@ -1214,9 +1214,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.macro_names.insert(ident); let is_macro_export = ast::attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { - ty::Visibility::Public + Visibility::Public } else { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) }; let binding = self.r.arenas.new_res_binding(res, vis.to_def_id(), span, expansion); self.r.set_binding_parent_module(binding, parent_scope.module); @@ -1258,7 +1258,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // Visibilities must not be resolved non-speculatively twice // and we already resolved this one as a `fn` item visibility. ItemKind::Fn(..) => { - self.try_resolve_visibility(&item.vis, false).unwrap_or(ty::Visibility::Public) + self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public) } _ => self.resolve_visibility(&item.vis), }; @@ -1492,7 +1492,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // If the variant is marked as non_exhaustive then lower the visibility to within the crate. let ctor_vis = if vis.is_public() && ast::attr::contains_name(&variant.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID) + Visibility::Restricted(CRATE_DEF_ID) } else { vis }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 59896ee88f4c..9a031ee03e0a 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -11,7 +11,8 @@ use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err}; use rustc_hir::def::{self, DefKind, PartialRes}; use rustc_hir::def_id::DefId; use rustc_middle::metadata::{ModChild, Reexport}; -use rustc_middle::{span_bug, ty}; +use rustc_middle::span_bug; +use rustc_middle::ty::Visibility; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, @@ -88,7 +89,7 @@ pub(crate) enum ImportKind<'ra> { is_prelude: bool, // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. - max_vis: Cell>, + max_vis: Cell>, id: NodeId, }, ExternCrate { @@ -185,7 +186,7 @@ pub(crate) struct ImportData<'ra> { /// |`use ::foo` | `ModuleOrUniformRoot::CrateRootAndExternPrelude` | a special case in 2015 edition | /// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - | pub imported_module: Cell>>, - pub vis: ty::Visibility, + pub vis: Visibility, } /// All imports are unique and allocated on a same arena, @@ -1280,7 +1281,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !binding.vis.is_at_least(import.vis, this.tcx) { reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis + if let Visibility::Restricted(binding_def_id) = binding.vis && binding_def_id.is_top_level_module() { crate_private_reexport = true; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 44a567f78100..3ef98100d094 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -28,7 +28,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, Par use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; -use rustc_middle::ty::DelegationFnSig; +use rustc_middle::ty::{DelegationFnSig, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint::{self, BuiltinLintDiag}; @@ -638,8 +638,8 @@ impl PathSource<'_, '_, '_> { enum MaybeExported<'a> { Ok(NodeId), Impl(Option), - ImplItem(Result), - NestedUse(&'a Visibility), + ImplItem(Result), + NestedUse(&'a ast::Visibility), } impl MaybeExported<'_> { @@ -3463,7 +3463,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { span, "error should be emitted when an unexpected trait item is used", ); - rustc_middle::ty::Visibility::Public + Visibility::Public }; this.r.feed_visibility(this.r.feed(id), vis); }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cf106a4892c7..5c72a6bcf708 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -65,7 +65,7 @@ use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{ self, DelegationFnSig, Feed, MainDefinition, RegisteredTools, ResolverGlobalCtxt, - ResolverOutputs, TyCtxt, TyCtxtFeed, + ResolverOutputs, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; @@ -748,7 +748,7 @@ struct NameBindingData<'ra> { warn_ambiguity: bool, expansion: LocalExpnId, span: Span, - vis: ty::Visibility, + vis: Visibility, } /// All name bindings are unique and allocated on a same arena, @@ -1083,7 +1083,7 @@ pub struct Resolver<'ra, 'tcx> { /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, glob_error: Option, - visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, + visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, @@ -1156,7 +1156,7 @@ pub struct Resolver<'ra, 'tcx> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility - struct_constructors: LocalDefIdMap<(Res, ty::Visibility, Vec>)>, + struct_constructors: LocalDefIdMap<(Res, Visibility, Vec>)>, lint_buffer: LintBuffer, @@ -1233,7 +1233,7 @@ impl<'ra> ResolverArenas<'ra> { fn new_res_binding( &'ra self, res: Res, - vis: ty::Visibility, + vis: Visibility, span: Span, expansion: LocalExpnId, ) -> NameBinding<'ra> { @@ -1603,7 +1603,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let root_parent_scope = ParentScope::module(graph_root, &resolver); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); - resolver.feed_visibility(crate_feed, ty::Visibility::Public); + resolver.feed_visibility(crate_feed, Visibility::Public); resolver } @@ -1657,7 +1657,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Default::default() } - fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: ty::Visibility) { + fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: Visibility) { let feed = feed.upgrade(self.tcx); feed.visibility(vis.to_def_id()); self.visibilities_for_hashing.push((feed.def_id(), vis)); @@ -2109,11 +2109,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.pat_span_map.insert(node, span); } - fn is_accessible_from( - &self, - vis: ty::Visibility>, - module: Module<'ra>, - ) -> bool { + fn is_accessible_from(&self, vis: Visibility>, module: Module<'ra>) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self.tcx) } From 7f398fd5f6444bb57196519c2dbe9554c51d8318 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 5 Jul 2025 22:47:02 +0300 Subject: [PATCH 64/64] resolve: Optimize `fn traits_in_module` --- compiler/rustc_resolve/src/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5c72a6bcf708..b0b29bc2eae2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -579,7 +579,7 @@ struct ModuleData<'ra> { globs: RefCell>>, /// Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell)]>>>, + traits: RefCell, Option>)]>>>, /// Span of the module itself. Used for error reporting. span: Span, @@ -655,12 +655,12 @@ impl<'ra> Module<'ra> { let mut traits = self.traits.borrow_mut(); if traits.is_none() { let mut collected_traits = Vec::new(); - self.for_each_child(resolver, |_, name, ns, binding| { + self.for_each_child(resolver, |r, name, ns, binding| { if ns != TypeNS { return; } - if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { - collected_traits.push((name, binding)) + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) = binding.res() { + collected_traits.push((name, binding, r.as_mut().get_module(def_id))) } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -1835,11 +1835,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { module.ensure_traits(self); let traits = module.traits.borrow(); - for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { - let trait_module = self.get_module(trait_binding.res().def_id()); + for &(trait_name, trait_binding, trait_module) in traits.as_ref().unwrap().iter() { if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); - let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); + let import_ids = self.find_transitive_imports(&trait_binding.kind, trait_name); found_traits.push(TraitCandidate { def_id, import_ids }); } }